xref: /openbmc/linux/fs/fuse/dir.c (revision fd72faac95d7e47610e981d7ed7b3c1529e55c88)
1e5e5558eSMiklos Szeredi /*
2e5e5558eSMiklos Szeredi   FUSE: Filesystem in Userspace
3e5e5558eSMiklos Szeredi   Copyright (C) 2001-2005  Miklos Szeredi <miklos@szeredi.hu>
4e5e5558eSMiklos Szeredi 
5e5e5558eSMiklos Szeredi   This program can be distributed under the terms of the GNU GPL.
6e5e5558eSMiklos Szeredi   See the file COPYING.
7e5e5558eSMiklos Szeredi */
8e5e5558eSMiklos Szeredi 
9e5e5558eSMiklos Szeredi #include "fuse_i.h"
10e5e5558eSMiklos Szeredi 
11e5e5558eSMiklos Szeredi #include <linux/pagemap.h>
12e5e5558eSMiklos Szeredi #include <linux/file.h>
13e5e5558eSMiklos Szeredi #include <linux/gfp.h>
14e5e5558eSMiklos Szeredi #include <linux/sched.h>
15e5e5558eSMiklos Szeredi #include <linux/namei.h>
16*fd72faacSMiklos Szeredi #include <linux/mount.h>
17e5e5558eSMiklos Szeredi 
18e5e5558eSMiklos Szeredi static inline unsigned long time_to_jiffies(unsigned long sec,
19e5e5558eSMiklos Szeredi 					    unsigned long nsec)
20e5e5558eSMiklos Szeredi {
21e5e5558eSMiklos Szeredi 	struct timespec ts = {sec, nsec};
22e5e5558eSMiklos Szeredi 	return jiffies + timespec_to_jiffies(&ts);
23e5e5558eSMiklos Szeredi }
24e5e5558eSMiklos Szeredi 
25e5e5558eSMiklos Szeredi static void fuse_lookup_init(struct fuse_req *req, struct inode *dir,
26e5e5558eSMiklos Szeredi 			     struct dentry *entry,
27e5e5558eSMiklos Szeredi 			     struct fuse_entry_out *outarg)
28e5e5558eSMiklos Szeredi {
29e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_LOOKUP;
30e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
31e5e5558eSMiklos Szeredi 	req->inode = dir;
32e5e5558eSMiklos Szeredi 	req->in.numargs = 1;
33e5e5558eSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
34e5e5558eSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
35e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
36e5e5558eSMiklos Szeredi 	req->out.args[0].size = sizeof(struct fuse_entry_out);
37e5e5558eSMiklos Szeredi 	req->out.args[0].value = outarg;
38e5e5558eSMiklos Szeredi }
39e5e5558eSMiklos Szeredi 
40e5e5558eSMiklos Szeredi static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
41e5e5558eSMiklos Szeredi {
42e5e5558eSMiklos Szeredi 	if (!entry->d_inode || is_bad_inode(entry->d_inode))
43e5e5558eSMiklos Szeredi 		return 0;
44e5e5558eSMiklos Szeredi 	else if (time_after(jiffies, entry->d_time)) {
45e5e5558eSMiklos Szeredi 		int err;
46e5e5558eSMiklos Szeredi 		struct fuse_entry_out outarg;
47e5e5558eSMiklos Szeredi 		struct inode *inode = entry->d_inode;
48e5e5558eSMiklos Szeredi 		struct fuse_inode *fi = get_fuse_inode(inode);
49e5e5558eSMiklos Szeredi 		struct fuse_conn *fc = get_fuse_conn(inode);
507c352bdfSMiklos Szeredi 		struct fuse_req *req = fuse_get_request(fc);
51e5e5558eSMiklos Szeredi 		if (!req)
52e5e5558eSMiklos Szeredi 			return 0;
53e5e5558eSMiklos Szeredi 
54e5e5558eSMiklos Szeredi 		fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
557c352bdfSMiklos Szeredi 		request_send(fc, req);
56e5e5558eSMiklos Szeredi 		err = req->out.h.error;
579e6268dbSMiklos Szeredi 		if (!err) {
589e6268dbSMiklos Szeredi 			if (outarg.nodeid != get_node_id(inode)) {
599e6268dbSMiklos Szeredi 				fuse_send_forget(fc, req, outarg.nodeid, 1);
609e6268dbSMiklos Szeredi 				return 0;
619e6268dbSMiklos Szeredi 			}
629e6268dbSMiklos Szeredi 			fi->nlookup ++;
639e6268dbSMiklos Szeredi 		}
64e5e5558eSMiklos Szeredi 		fuse_put_request(fc, req);
659e6268dbSMiklos Szeredi 		if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
66e5e5558eSMiklos Szeredi 			return 0;
67e5e5558eSMiklos Szeredi 
68e5e5558eSMiklos Szeredi 		fuse_change_attributes(inode, &outarg.attr);
69e5e5558eSMiklos Szeredi 		entry->d_time = time_to_jiffies(outarg.entry_valid,
70e5e5558eSMiklos Szeredi 						outarg.entry_valid_nsec);
71e5e5558eSMiklos Szeredi 		fi->i_time = time_to_jiffies(outarg.attr_valid,
72e5e5558eSMiklos Szeredi 					     outarg.attr_valid_nsec);
73e5e5558eSMiklos Szeredi 	}
74e5e5558eSMiklos Szeredi 	return 1;
75e5e5558eSMiklos Szeredi }
76e5e5558eSMiklos Szeredi 
77e5e5558eSMiklos Szeredi static struct dentry_operations fuse_dentry_operations = {
78e5e5558eSMiklos Szeredi 	.d_revalidate	= fuse_dentry_revalidate,
79e5e5558eSMiklos Szeredi };
80e5e5558eSMiklos Szeredi 
81e5e5558eSMiklos Szeredi static int fuse_lookup_iget(struct inode *dir, struct dentry *entry,
82e5e5558eSMiklos Szeredi 			    struct inode **inodep)
83e5e5558eSMiklos Szeredi {
84e5e5558eSMiklos Szeredi 	int err;
85e5e5558eSMiklos Szeredi 	struct fuse_entry_out outarg;
86e5e5558eSMiklos Szeredi 	struct inode *inode = NULL;
87e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
88e5e5558eSMiklos Szeredi 	struct fuse_req *req;
89e5e5558eSMiklos Szeredi 
90e5e5558eSMiklos Szeredi 	if (entry->d_name.len > FUSE_NAME_MAX)
91e5e5558eSMiklos Szeredi 		return -ENAMETOOLONG;
92e5e5558eSMiklos Szeredi 
93e5e5558eSMiklos Szeredi 	req = fuse_get_request(fc);
94e5e5558eSMiklos Szeredi 	if (!req)
957c352bdfSMiklos Szeredi 		return -EINTR;
96e5e5558eSMiklos Szeredi 
97e5e5558eSMiklos Szeredi 	fuse_lookup_init(req, dir, entry, &outarg);
98e5e5558eSMiklos Szeredi 	request_send(fc, req);
99e5e5558eSMiklos Szeredi 	err = req->out.h.error;
100ee4e5271SMiklos Szeredi 	if (!err && (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID))
101ee4e5271SMiklos Szeredi 		err = -EIO;
102e5e5558eSMiklos Szeredi 	if (!err) {
103e5e5558eSMiklos Szeredi 		inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
1049e6268dbSMiklos Szeredi 				  &outarg.attr);
105e5e5558eSMiklos Szeredi 		if (!inode) {
1069e6268dbSMiklos Szeredi 			fuse_send_forget(fc, req, outarg.nodeid, 1);
107e5e5558eSMiklos Szeredi 			return -ENOMEM;
108e5e5558eSMiklos Szeredi 		}
109e5e5558eSMiklos Szeredi 	}
110e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
111e5e5558eSMiklos Szeredi 	if (err && err != -ENOENT)
112e5e5558eSMiklos Szeredi 		return err;
113e5e5558eSMiklos Szeredi 
114e5e5558eSMiklos Szeredi 	if (inode) {
115e5e5558eSMiklos Szeredi 		struct fuse_inode *fi = get_fuse_inode(inode);
116e5e5558eSMiklos Szeredi 		entry->d_time =	time_to_jiffies(outarg.entry_valid,
117e5e5558eSMiklos Szeredi 						outarg.entry_valid_nsec);
118e5e5558eSMiklos Szeredi 		fi->i_time = time_to_jiffies(outarg.attr_valid,
119e5e5558eSMiklos Szeredi 					     outarg.attr_valid_nsec);
120e5e5558eSMiklos Szeredi 	}
121e5e5558eSMiklos Szeredi 
122e5e5558eSMiklos Szeredi 	entry->d_op = &fuse_dentry_operations;
123e5e5558eSMiklos Szeredi 	*inodep = inode;
124e5e5558eSMiklos Szeredi 	return 0;
125e5e5558eSMiklos Szeredi }
126e5e5558eSMiklos Szeredi 
1279e6268dbSMiklos Szeredi void fuse_invalidate_attr(struct inode *inode)
1289e6268dbSMiklos Szeredi {
1299e6268dbSMiklos Szeredi 	get_fuse_inode(inode)->i_time = jiffies - 1;
1309e6268dbSMiklos Szeredi }
1319e6268dbSMiklos Szeredi 
1329e6268dbSMiklos Szeredi static void fuse_invalidate_entry(struct dentry *entry)
1339e6268dbSMiklos Szeredi {
1349e6268dbSMiklos Szeredi 	d_invalidate(entry);
1359e6268dbSMiklos Szeredi 	entry->d_time = jiffies - 1;
1369e6268dbSMiklos Szeredi }
1379e6268dbSMiklos Szeredi 
138*fd72faacSMiklos Szeredi static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode,
139*fd72faacSMiklos Szeredi 			    struct nameidata *nd)
140*fd72faacSMiklos Szeredi {
141*fd72faacSMiklos Szeredi 	int err;
142*fd72faacSMiklos Szeredi 	struct inode *inode;
143*fd72faacSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
144*fd72faacSMiklos Szeredi 	struct fuse_req *req;
145*fd72faacSMiklos Szeredi 	struct fuse_open_in inarg;
146*fd72faacSMiklos Szeredi 	struct fuse_open_out outopen;
147*fd72faacSMiklos Szeredi 	struct fuse_entry_out outentry;
148*fd72faacSMiklos Szeredi 	struct fuse_inode *fi;
149*fd72faacSMiklos Szeredi 	struct fuse_file *ff;
150*fd72faacSMiklos Szeredi 	struct file *file;
151*fd72faacSMiklos Szeredi 	int flags = nd->intent.open.flags - 1;
152*fd72faacSMiklos Szeredi 
153*fd72faacSMiklos Szeredi 	err = -ENOSYS;
154*fd72faacSMiklos Szeredi 	if (fc->no_create)
155*fd72faacSMiklos Szeredi 		goto out;
156*fd72faacSMiklos Szeredi 
157*fd72faacSMiklos Szeredi 	err = -ENAMETOOLONG;
158*fd72faacSMiklos Szeredi 	if (entry->d_name.len > FUSE_NAME_MAX)
159*fd72faacSMiklos Szeredi 		goto out;
160*fd72faacSMiklos Szeredi 
161*fd72faacSMiklos Szeredi 	err = -EINTR;
162*fd72faacSMiklos Szeredi 	req = fuse_get_request(fc);
163*fd72faacSMiklos Szeredi 	if (!req)
164*fd72faacSMiklos Szeredi 		goto out;
165*fd72faacSMiklos Szeredi 
166*fd72faacSMiklos Szeredi 	ff = fuse_file_alloc();
167*fd72faacSMiklos Szeredi 	if (!ff)
168*fd72faacSMiklos Szeredi 		goto out_put_request;
169*fd72faacSMiklos Szeredi 
170*fd72faacSMiklos Szeredi 	flags &= ~O_NOCTTY;
171*fd72faacSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
172*fd72faacSMiklos Szeredi 	inarg.flags = flags;
173*fd72faacSMiklos Szeredi 	inarg.mode = mode;
174*fd72faacSMiklos Szeredi 	req->in.h.opcode = FUSE_CREATE;
175*fd72faacSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
176*fd72faacSMiklos Szeredi 	req->inode = dir;
177*fd72faacSMiklos Szeredi 	req->in.numargs = 2;
178*fd72faacSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
179*fd72faacSMiklos Szeredi 	req->in.args[0].value = &inarg;
180*fd72faacSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
181*fd72faacSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
182*fd72faacSMiklos Szeredi 	req->out.numargs = 2;
183*fd72faacSMiklos Szeredi 	req->out.args[0].size = sizeof(outentry);
184*fd72faacSMiklos Szeredi 	req->out.args[0].value = &outentry;
185*fd72faacSMiklos Szeredi 	req->out.args[1].size = sizeof(outopen);
186*fd72faacSMiklos Szeredi 	req->out.args[1].value = &outopen;
187*fd72faacSMiklos Szeredi 	request_send(fc, req);
188*fd72faacSMiklos Szeredi 	err = req->out.h.error;
189*fd72faacSMiklos Szeredi 	if (err) {
190*fd72faacSMiklos Szeredi 		if (err == -ENOSYS)
191*fd72faacSMiklos Szeredi 			fc->no_create = 1;
192*fd72faacSMiklos Szeredi 		goto out_free_ff;
193*fd72faacSMiklos Szeredi 	}
194*fd72faacSMiklos Szeredi 
195*fd72faacSMiklos Szeredi 	err = -EIO;
196*fd72faacSMiklos Szeredi 	if (!S_ISREG(outentry.attr.mode))
197*fd72faacSMiklos Szeredi 		goto out_free_ff;
198*fd72faacSMiklos Szeredi 
199*fd72faacSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation,
200*fd72faacSMiklos Szeredi 			  &outentry.attr);
201*fd72faacSMiklos Szeredi 	err = -ENOMEM;
202*fd72faacSMiklos Szeredi 	if (!inode) {
203*fd72faacSMiklos Szeredi 		flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
204*fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
205*fd72faacSMiklos Szeredi 		fuse_send_release(fc, ff, outentry.nodeid, NULL, flags, 0);
206*fd72faacSMiklos Szeredi 		goto out_put_request;
207*fd72faacSMiklos Szeredi 	}
208*fd72faacSMiklos Szeredi 	fuse_put_request(fc, req);
209*fd72faacSMiklos Szeredi 	entry->d_time =	time_to_jiffies(outentry.entry_valid,
210*fd72faacSMiklos Szeredi 					outentry.entry_valid_nsec);
211*fd72faacSMiklos Szeredi 	fi = get_fuse_inode(inode);
212*fd72faacSMiklos Szeredi 	fi->i_time = time_to_jiffies(outentry.attr_valid,
213*fd72faacSMiklos Szeredi 				     outentry.attr_valid_nsec);
214*fd72faacSMiklos Szeredi 
215*fd72faacSMiklos Szeredi 	d_instantiate(entry, inode);
216*fd72faacSMiklos Szeredi 	file = lookup_instantiate_filp(nd, entry, generic_file_open);
217*fd72faacSMiklos Szeredi 	if (IS_ERR(file)) {
218*fd72faacSMiklos Szeredi 		ff->fh = outopen.fh;
219*fd72faacSMiklos Szeredi 		fuse_send_release(fc, ff, outentry.nodeid, inode, flags, 0);
220*fd72faacSMiklos Szeredi 		return PTR_ERR(file);
221*fd72faacSMiklos Szeredi 	}
222*fd72faacSMiklos Szeredi 	fuse_finish_open(inode, file, ff, &outopen);
223*fd72faacSMiklos Szeredi 	return 0;
224*fd72faacSMiklos Szeredi 
225*fd72faacSMiklos Szeredi  out_free_ff:
226*fd72faacSMiklos Szeredi 	fuse_file_free(ff);
227*fd72faacSMiklos Szeredi  out_put_request:
228*fd72faacSMiklos Szeredi 	fuse_put_request(fc, req);
229*fd72faacSMiklos Szeredi  out:
230*fd72faacSMiklos Szeredi 	return err;
231*fd72faacSMiklos Szeredi }
232*fd72faacSMiklos Szeredi 
2339e6268dbSMiklos Szeredi static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
2349e6268dbSMiklos Szeredi 			    struct inode *dir, struct dentry *entry,
2359e6268dbSMiklos Szeredi 			    int mode)
2369e6268dbSMiklos Szeredi {
2379e6268dbSMiklos Szeredi 	struct fuse_entry_out outarg;
2389e6268dbSMiklos Szeredi 	struct inode *inode;
2399e6268dbSMiklos Szeredi 	struct fuse_inode *fi;
2409e6268dbSMiklos Szeredi 	int err;
2419e6268dbSMiklos Szeredi 
2429e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
2439e6268dbSMiklos Szeredi 	req->inode = dir;
2449e6268dbSMiklos Szeredi 	req->out.numargs = 1;
2459e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
2469e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
2479e6268dbSMiklos Szeredi 	request_send(fc, req);
2489e6268dbSMiklos Szeredi 	err = req->out.h.error;
2499e6268dbSMiklos Szeredi 	if (err) {
2509e6268dbSMiklos Szeredi 		fuse_put_request(fc, req);
2519e6268dbSMiklos Szeredi 		return err;
2529e6268dbSMiklos Szeredi 	}
253ee4e5271SMiklos Szeredi 	if (!outarg.nodeid || outarg.nodeid == FUSE_ROOT_ID) {
254ee4e5271SMiklos Szeredi 		fuse_put_request(fc, req);
255ee4e5271SMiklos Szeredi 		return -EIO;
256ee4e5271SMiklos Szeredi 	}
2579e6268dbSMiklos Szeredi 	inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation,
2589e6268dbSMiklos Szeredi 			  &outarg.attr);
2599e6268dbSMiklos Szeredi 	if (!inode) {
2609e6268dbSMiklos Szeredi 		fuse_send_forget(fc, req, outarg.nodeid, 1);
2619e6268dbSMiklos Szeredi 		return -ENOMEM;
2629e6268dbSMiklos Szeredi 	}
2639e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
2649e6268dbSMiklos Szeredi 
2659e6268dbSMiklos Szeredi 	/* Don't allow userspace to do really stupid things... */
2669e6268dbSMiklos Szeredi 	if ((inode->i_mode ^ mode) & S_IFMT) {
2679e6268dbSMiklos Szeredi 		iput(inode);
2689e6268dbSMiklos Szeredi 		return -EIO;
2699e6268dbSMiklos Szeredi 	}
2709e6268dbSMiklos Szeredi 
2719e6268dbSMiklos Szeredi 	entry->d_time = time_to_jiffies(outarg.entry_valid,
2729e6268dbSMiklos Szeredi 					outarg.entry_valid_nsec);
2739e6268dbSMiklos Szeredi 
2749e6268dbSMiklos Szeredi 	fi = get_fuse_inode(inode);
2759e6268dbSMiklos Szeredi 	fi->i_time = time_to_jiffies(outarg.attr_valid,
2769e6268dbSMiklos Szeredi 				     outarg.attr_valid_nsec);
2779e6268dbSMiklos Szeredi 
2789e6268dbSMiklos Szeredi 	d_instantiate(entry, inode);
2799e6268dbSMiklos Szeredi 	fuse_invalidate_attr(dir);
2809e6268dbSMiklos Szeredi 	return 0;
2819e6268dbSMiklos Szeredi }
2829e6268dbSMiklos Szeredi 
2839e6268dbSMiklos Szeredi static int fuse_mknod(struct inode *dir, struct dentry *entry, int mode,
2849e6268dbSMiklos Szeredi 		      dev_t rdev)
2859e6268dbSMiklos Szeredi {
2869e6268dbSMiklos Szeredi 	struct fuse_mknod_in inarg;
2879e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
2889e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
2899e6268dbSMiklos Szeredi 	if (!req)
2907c352bdfSMiklos Szeredi 		return -EINTR;
2919e6268dbSMiklos Szeredi 
2929e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
2939e6268dbSMiklos Szeredi 	inarg.mode = mode;
2949e6268dbSMiklos Szeredi 	inarg.rdev = new_encode_dev(rdev);
2959e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKNOD;
2969e6268dbSMiklos Szeredi 	req->in.numargs = 2;
2979e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
2989e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
2999e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
3009e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
3019e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, mode);
3029e6268dbSMiklos Szeredi }
3039e6268dbSMiklos Szeredi 
3049e6268dbSMiklos Szeredi static int fuse_create(struct inode *dir, struct dentry *entry, int mode,
3059e6268dbSMiklos Szeredi 		       struct nameidata *nd)
3069e6268dbSMiklos Szeredi {
307*fd72faacSMiklos Szeredi 	if (nd && (nd->flags & LOOKUP_CREATE)) {
308*fd72faacSMiklos Szeredi 		int err = fuse_create_open(dir, entry, mode, nd);
309*fd72faacSMiklos Szeredi 		if (err != -ENOSYS)
310*fd72faacSMiklos Szeredi 			return err;
311*fd72faacSMiklos Szeredi 		/* Fall back on mknod */
312*fd72faacSMiklos Szeredi 	}
3139e6268dbSMiklos Szeredi 	return fuse_mknod(dir, entry, mode, 0);
3149e6268dbSMiklos Szeredi }
3159e6268dbSMiklos Szeredi 
3169e6268dbSMiklos Szeredi static int fuse_mkdir(struct inode *dir, struct dentry *entry, int mode)
3179e6268dbSMiklos Szeredi {
3189e6268dbSMiklos Szeredi 	struct fuse_mkdir_in inarg;
3199e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
3209e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
3219e6268dbSMiklos Szeredi 	if (!req)
3227c352bdfSMiklos Szeredi 		return -EINTR;
3239e6268dbSMiklos Szeredi 
3249e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
3259e6268dbSMiklos Szeredi 	inarg.mode = mode;
3269e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_MKDIR;
3279e6268dbSMiklos Szeredi 	req->in.numargs = 2;
3289e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
3299e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
3309e6268dbSMiklos Szeredi 	req->in.args[1].size = entry->d_name.len + 1;
3319e6268dbSMiklos Szeredi 	req->in.args[1].value = entry->d_name.name;
3329e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFDIR);
3339e6268dbSMiklos Szeredi }
3349e6268dbSMiklos Szeredi 
3359e6268dbSMiklos Szeredi static int fuse_symlink(struct inode *dir, struct dentry *entry,
3369e6268dbSMiklos Szeredi 			const char *link)
3379e6268dbSMiklos Szeredi {
3389e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
3399e6268dbSMiklos Szeredi 	unsigned len = strlen(link) + 1;
3409e6268dbSMiklos Szeredi 	struct fuse_req *req;
3419e6268dbSMiklos Szeredi 
3429e6268dbSMiklos Szeredi 	if (len > FUSE_SYMLINK_MAX)
3439e6268dbSMiklos Szeredi 		return -ENAMETOOLONG;
3449e6268dbSMiklos Szeredi 
3459e6268dbSMiklos Szeredi 	req = fuse_get_request(fc);
3469e6268dbSMiklos Szeredi 	if (!req)
3477c352bdfSMiklos Szeredi 		return -EINTR;
3489e6268dbSMiklos Szeredi 
3499e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SYMLINK;
3509e6268dbSMiklos Szeredi 	req->in.numargs = 2;
3519e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
3529e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
3539e6268dbSMiklos Szeredi 	req->in.args[1].size = len;
3549e6268dbSMiklos Szeredi 	req->in.args[1].value = link;
3559e6268dbSMiklos Szeredi 	return create_new_entry(fc, req, dir, entry, S_IFLNK);
3569e6268dbSMiklos Szeredi }
3579e6268dbSMiklos Szeredi 
3589e6268dbSMiklos Szeredi static int fuse_unlink(struct inode *dir, struct dentry *entry)
3599e6268dbSMiklos Szeredi {
3609e6268dbSMiklos Szeredi 	int err;
3619e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
3629e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
3639e6268dbSMiklos Szeredi 	if (!req)
3647c352bdfSMiklos Szeredi 		return -EINTR;
3659e6268dbSMiklos Szeredi 
3669e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_UNLINK;
3679e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
3689e6268dbSMiklos Szeredi 	req->inode = dir;
3699e6268dbSMiklos Szeredi 	req->in.numargs = 1;
3709e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
3719e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
3729e6268dbSMiklos Szeredi 	request_send(fc, req);
3739e6268dbSMiklos Szeredi 	err = req->out.h.error;
3749e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
3759e6268dbSMiklos Szeredi 	if (!err) {
3769e6268dbSMiklos Szeredi 		struct inode *inode = entry->d_inode;
3779e6268dbSMiklos Szeredi 
3789e6268dbSMiklos Szeredi 		/* Set nlink to zero so the inode can be cleared, if
3799e6268dbSMiklos Szeredi                    the inode does have more links this will be
3809e6268dbSMiklos Szeredi                    discovered at the next lookup/getattr */
3819e6268dbSMiklos Szeredi 		inode->i_nlink = 0;
3829e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
3839e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
3849e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
3859e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
3869e6268dbSMiklos Szeredi 	return err;
3879e6268dbSMiklos Szeredi }
3889e6268dbSMiklos Szeredi 
3899e6268dbSMiklos Szeredi static int fuse_rmdir(struct inode *dir, struct dentry *entry)
3909e6268dbSMiklos Szeredi {
3919e6268dbSMiklos Szeredi 	int err;
3929e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(dir);
3939e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
3949e6268dbSMiklos Szeredi 	if (!req)
3957c352bdfSMiklos Szeredi 		return -EINTR;
3969e6268dbSMiklos Szeredi 
3979e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RMDIR;
3989e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(dir);
3999e6268dbSMiklos Szeredi 	req->inode = dir;
4009e6268dbSMiklos Szeredi 	req->in.numargs = 1;
4019e6268dbSMiklos Szeredi 	req->in.args[0].size = entry->d_name.len + 1;
4029e6268dbSMiklos Szeredi 	req->in.args[0].value = entry->d_name.name;
4039e6268dbSMiklos Szeredi 	request_send(fc, req);
4049e6268dbSMiklos Szeredi 	err = req->out.h.error;
4059e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
4069e6268dbSMiklos Szeredi 	if (!err) {
4079e6268dbSMiklos Szeredi 		entry->d_inode->i_nlink = 0;
4089e6268dbSMiklos Szeredi 		fuse_invalidate_attr(dir);
4099e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
4109e6268dbSMiklos Szeredi 		fuse_invalidate_entry(entry);
4119e6268dbSMiklos Szeredi 	return err;
4129e6268dbSMiklos Szeredi }
4139e6268dbSMiklos Szeredi 
4149e6268dbSMiklos Szeredi static int fuse_rename(struct inode *olddir, struct dentry *oldent,
4159e6268dbSMiklos Szeredi 		       struct inode *newdir, struct dentry *newent)
4169e6268dbSMiklos Szeredi {
4179e6268dbSMiklos Szeredi 	int err;
4189e6268dbSMiklos Szeredi 	struct fuse_rename_in inarg;
4199e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(olddir);
4209e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
4219e6268dbSMiklos Szeredi 	if (!req)
4227c352bdfSMiklos Szeredi 		return -EINTR;
4239e6268dbSMiklos Szeredi 
4249e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
4259e6268dbSMiklos Szeredi 	inarg.newdir = get_node_id(newdir);
4269e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_RENAME;
4279e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(olddir);
4289e6268dbSMiklos Szeredi 	req->inode = olddir;
4299e6268dbSMiklos Szeredi 	req->inode2 = newdir;
4309e6268dbSMiklos Szeredi 	req->in.numargs = 3;
4319e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
4329e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
4339e6268dbSMiklos Szeredi 	req->in.args[1].size = oldent->d_name.len + 1;
4349e6268dbSMiklos Szeredi 	req->in.args[1].value = oldent->d_name.name;
4359e6268dbSMiklos Szeredi 	req->in.args[2].size = newent->d_name.len + 1;
4369e6268dbSMiklos Szeredi 	req->in.args[2].value = newent->d_name.name;
4379e6268dbSMiklos Szeredi 	request_send(fc, req);
4389e6268dbSMiklos Szeredi 	err = req->out.h.error;
4399e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
4409e6268dbSMiklos Szeredi 	if (!err) {
4419e6268dbSMiklos Szeredi 		fuse_invalidate_attr(olddir);
4429e6268dbSMiklos Szeredi 		if (olddir != newdir)
4439e6268dbSMiklos Szeredi 			fuse_invalidate_attr(newdir);
4449e6268dbSMiklos Szeredi 	} else if (err == -EINTR) {
4459e6268dbSMiklos Szeredi 		/* If request was interrupted, DEITY only knows if the
4469e6268dbSMiklos Szeredi 		   rename actually took place.  If the invalidation
4479e6268dbSMiklos Szeredi 		   fails (e.g. some process has CWD under the renamed
4489e6268dbSMiklos Szeredi 		   directory), then there can be inconsistency between
4499e6268dbSMiklos Szeredi 		   the dcache and the real filesystem.  Tough luck. */
4509e6268dbSMiklos Szeredi 		fuse_invalidate_entry(oldent);
4519e6268dbSMiklos Szeredi 		if (newent->d_inode)
4529e6268dbSMiklos Szeredi 			fuse_invalidate_entry(newent);
4539e6268dbSMiklos Szeredi 	}
4549e6268dbSMiklos Szeredi 
4559e6268dbSMiklos Szeredi 	return err;
4569e6268dbSMiklos Szeredi }
4579e6268dbSMiklos Szeredi 
4589e6268dbSMiklos Szeredi static int fuse_link(struct dentry *entry, struct inode *newdir,
4599e6268dbSMiklos Szeredi 		     struct dentry *newent)
4609e6268dbSMiklos Szeredi {
4619e6268dbSMiklos Szeredi 	int err;
4629e6268dbSMiklos Szeredi 	struct fuse_link_in inarg;
4639e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
4649e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
4659e6268dbSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
4669e6268dbSMiklos Szeredi 	if (!req)
4677c352bdfSMiklos Szeredi 		return -EINTR;
4689e6268dbSMiklos Szeredi 
4699e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
4709e6268dbSMiklos Szeredi 	inarg.oldnodeid = get_node_id(inode);
4719e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_LINK;
4729e6268dbSMiklos Szeredi 	req->inode2 = inode;
4739e6268dbSMiklos Szeredi 	req->in.numargs = 2;
4749e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
4759e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
4769e6268dbSMiklos Szeredi 	req->in.args[1].size = newent->d_name.len + 1;
4779e6268dbSMiklos Szeredi 	req->in.args[1].value = newent->d_name.name;
4789e6268dbSMiklos Szeredi 	err = create_new_entry(fc, req, newdir, newent, inode->i_mode);
4799e6268dbSMiklos Szeredi 	/* Contrary to "normal" filesystems it can happen that link
4809e6268dbSMiklos Szeredi 	   makes two "logical" inodes point to the same "physical"
4819e6268dbSMiklos Szeredi 	   inode.  We invalidate the attributes of the old one, so it
4829e6268dbSMiklos Szeredi 	   will reflect changes in the backing inode (link count,
4839e6268dbSMiklos Szeredi 	   etc.)
4849e6268dbSMiklos Szeredi 	*/
4859e6268dbSMiklos Szeredi 	if (!err || err == -EINTR)
4869e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
4879e6268dbSMiklos Szeredi 	return err;
4889e6268dbSMiklos Szeredi }
4899e6268dbSMiklos Szeredi 
490e5e5558eSMiklos Szeredi int fuse_do_getattr(struct inode *inode)
491e5e5558eSMiklos Szeredi {
492e5e5558eSMiklos Szeredi 	int err;
493e5e5558eSMiklos Szeredi 	struct fuse_attr_out arg;
494e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
495e5e5558eSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
496e5e5558eSMiklos Szeredi 	if (!req)
4977c352bdfSMiklos Szeredi 		return -EINTR;
498e5e5558eSMiklos Szeredi 
499e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETATTR;
500e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
501e5e5558eSMiklos Szeredi 	req->inode = inode;
502e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
503e5e5558eSMiklos Szeredi 	req->out.args[0].size = sizeof(arg);
504e5e5558eSMiklos Szeredi 	req->out.args[0].value = &arg;
505e5e5558eSMiklos Szeredi 	request_send(fc, req);
506e5e5558eSMiklos Szeredi 	err = req->out.h.error;
507e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
508e5e5558eSMiklos Szeredi 	if (!err) {
509e5e5558eSMiklos Szeredi 		if ((inode->i_mode ^ arg.attr.mode) & S_IFMT) {
510e5e5558eSMiklos Szeredi 			make_bad_inode(inode);
511e5e5558eSMiklos Szeredi 			err = -EIO;
512e5e5558eSMiklos Szeredi 		} else {
513e5e5558eSMiklos Szeredi 			struct fuse_inode *fi = get_fuse_inode(inode);
514e5e5558eSMiklos Szeredi 			fuse_change_attributes(inode, &arg.attr);
515e5e5558eSMiklos Szeredi 			fi->i_time = time_to_jiffies(arg.attr_valid,
516e5e5558eSMiklos Szeredi 						     arg.attr_valid_nsec);
517e5e5558eSMiklos Szeredi 		}
518e5e5558eSMiklos Szeredi 	}
519e5e5558eSMiklos Szeredi 	return err;
520e5e5558eSMiklos Szeredi }
521e5e5558eSMiklos Szeredi 
52287729a55SMiklos Szeredi /*
52387729a55SMiklos Szeredi  * Calling into a user-controlled filesystem gives the filesystem
52487729a55SMiklos Szeredi  * daemon ptrace-like capabilities over the requester process.  This
52587729a55SMiklos Szeredi  * means, that the filesystem daemon is able to record the exact
52687729a55SMiklos Szeredi  * filesystem operations performed, and can also control the behavior
52787729a55SMiklos Szeredi  * of the requester process in otherwise impossible ways.  For example
52887729a55SMiklos Szeredi  * it can delay the operation for arbitrary length of time allowing
52987729a55SMiklos Szeredi  * DoS against the requester.
53087729a55SMiklos Szeredi  *
53187729a55SMiklos Szeredi  * For this reason only those processes can call into the filesystem,
53287729a55SMiklos Szeredi  * for which the owner of the mount has ptrace privilege.  This
53387729a55SMiklos Szeredi  * excludes processes started by other users, suid or sgid processes.
53487729a55SMiklos Szeredi  */
53587729a55SMiklos Szeredi static int fuse_allow_task(struct fuse_conn *fc, struct task_struct *task)
53687729a55SMiklos Szeredi {
53787729a55SMiklos Szeredi 	if (fc->flags & FUSE_ALLOW_OTHER)
53887729a55SMiklos Szeredi 		return 1;
53987729a55SMiklos Szeredi 
54087729a55SMiklos Szeredi 	if (task->euid == fc->user_id &&
54187729a55SMiklos Szeredi 	    task->suid == fc->user_id &&
54287729a55SMiklos Szeredi 	    task->uid == fc->user_id &&
54387729a55SMiklos Szeredi 	    task->egid == fc->group_id &&
54487729a55SMiklos Szeredi 	    task->sgid == fc->group_id &&
54587729a55SMiklos Szeredi 	    task->gid == fc->group_id)
54687729a55SMiklos Szeredi 		return 1;
54787729a55SMiklos Szeredi 
54887729a55SMiklos Szeredi 	return 0;
54987729a55SMiklos Szeredi }
55087729a55SMiklos Szeredi 
551e5e5558eSMiklos Szeredi static int fuse_revalidate(struct dentry *entry)
552e5e5558eSMiklos Szeredi {
553e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
554e5e5558eSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
555e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
556e5e5558eSMiklos Szeredi 
55787729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
558e5e5558eSMiklos Szeredi 		return -EACCES;
55987729a55SMiklos Szeredi 	if (get_node_id(inode) != FUSE_ROOT_ID &&
56087729a55SMiklos Szeredi 	    time_before_eq(jiffies, fi->i_time))
561e5e5558eSMiklos Szeredi 		return 0;
562e5e5558eSMiklos Szeredi 
563e5e5558eSMiklos Szeredi 	return fuse_do_getattr(inode);
564e5e5558eSMiklos Szeredi }
565e5e5558eSMiklos Szeredi 
56631d40d74SMiklos Szeredi static int fuse_access(struct inode *inode, int mask)
56731d40d74SMiklos Szeredi {
56831d40d74SMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
56931d40d74SMiklos Szeredi 	struct fuse_req *req;
57031d40d74SMiklos Szeredi 	struct fuse_access_in inarg;
57131d40d74SMiklos Szeredi 	int err;
57231d40d74SMiklos Szeredi 
57331d40d74SMiklos Szeredi 	if (fc->no_access)
57431d40d74SMiklos Szeredi 		return 0;
57531d40d74SMiklos Szeredi 
57631d40d74SMiklos Szeredi 	req = fuse_get_request(fc);
57731d40d74SMiklos Szeredi 	if (!req)
57831d40d74SMiklos Szeredi 		return -EINTR;
57931d40d74SMiklos Szeredi 
58031d40d74SMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
58131d40d74SMiklos Szeredi 	inarg.mask = mask;
58231d40d74SMiklos Szeredi 	req->in.h.opcode = FUSE_ACCESS;
58331d40d74SMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
58431d40d74SMiklos Szeredi 	req->inode = inode;
58531d40d74SMiklos Szeredi 	req->in.numargs = 1;
58631d40d74SMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
58731d40d74SMiklos Szeredi 	req->in.args[0].value = &inarg;
58831d40d74SMiklos Szeredi 	request_send(fc, req);
58931d40d74SMiklos Szeredi 	err = req->out.h.error;
59031d40d74SMiklos Szeredi 	fuse_put_request(fc, req);
59131d40d74SMiklos Szeredi 	if (err == -ENOSYS) {
59231d40d74SMiklos Szeredi 		fc->no_access = 1;
59331d40d74SMiklos Szeredi 		err = 0;
59431d40d74SMiklos Szeredi 	}
59531d40d74SMiklos Szeredi 	return err;
59631d40d74SMiklos Szeredi }
59731d40d74SMiklos Szeredi 
598e5e5558eSMiklos Szeredi static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
599e5e5558eSMiklos Szeredi {
600e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
601e5e5558eSMiklos Szeredi 
60287729a55SMiklos Szeredi 	if (!fuse_allow_task(fc, current))
603e5e5558eSMiklos Szeredi 		return -EACCES;
6041e9a4ed9SMiklos Szeredi 	else if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
6051e9a4ed9SMiklos Szeredi 		int err = generic_permission(inode, mask, NULL);
6061e9a4ed9SMiklos Szeredi 
6071e9a4ed9SMiklos Szeredi 		/* If permission is denied, try to refresh file
6081e9a4ed9SMiklos Szeredi 		   attributes.  This is also needed, because the root
6091e9a4ed9SMiklos Szeredi 		   node will at first have no permissions */
6101e9a4ed9SMiklos Szeredi 		if (err == -EACCES) {
6111e9a4ed9SMiklos Szeredi 		 	err = fuse_do_getattr(inode);
6121e9a4ed9SMiklos Szeredi 			if (!err)
6131e9a4ed9SMiklos Szeredi 				err = generic_permission(inode, mask, NULL);
6141e9a4ed9SMiklos Szeredi 		}
6151e9a4ed9SMiklos Szeredi 
6161e9a4ed9SMiklos Szeredi 		/* FIXME: Need some mechanism to revoke permissions:
6171e9a4ed9SMiklos Szeredi 		   currently if the filesystem suddenly changes the
6181e9a4ed9SMiklos Szeredi 		   file mode, we will not be informed about it, and
6191e9a4ed9SMiklos Szeredi 		   continue to allow access to the file/directory.
6201e9a4ed9SMiklos Szeredi 
6211e9a4ed9SMiklos Szeredi 		   This is actually not so grave, since the user can
6221e9a4ed9SMiklos Szeredi 		   simply keep access to the file/directory anyway by
6231e9a4ed9SMiklos Szeredi 		   keeping it open... */
6241e9a4ed9SMiklos Szeredi 
6251e9a4ed9SMiklos Szeredi 		return err;
6261e9a4ed9SMiklos Szeredi 	} else {
627e5e5558eSMiklos Szeredi 		int mode = inode->i_mode;
628e5e5558eSMiklos Szeredi 		if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
629e5e5558eSMiklos Szeredi 			return -EACCES;
63031d40d74SMiklos Szeredi 
63131d40d74SMiklos Szeredi 		if (nd && (nd->flags & LOOKUP_ACCESS))
63231d40d74SMiklos Szeredi 			return fuse_access(inode, mask);
633e5e5558eSMiklos Szeredi 		return 0;
634e5e5558eSMiklos Szeredi 	}
635e5e5558eSMiklos Szeredi }
636e5e5558eSMiklos Szeredi 
637e5e5558eSMiklos Szeredi static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
638e5e5558eSMiklos Szeredi 			 void *dstbuf, filldir_t filldir)
639e5e5558eSMiklos Szeredi {
640e5e5558eSMiklos Szeredi 	while (nbytes >= FUSE_NAME_OFFSET) {
641e5e5558eSMiklos Szeredi 		struct fuse_dirent *dirent = (struct fuse_dirent *) buf;
642e5e5558eSMiklos Szeredi 		size_t reclen = FUSE_DIRENT_SIZE(dirent);
643e5e5558eSMiklos Szeredi 		int over;
644e5e5558eSMiklos Szeredi 		if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
645e5e5558eSMiklos Szeredi 			return -EIO;
646e5e5558eSMiklos Szeredi 		if (reclen > nbytes)
647e5e5558eSMiklos Szeredi 			break;
648e5e5558eSMiklos Szeredi 
649e5e5558eSMiklos Szeredi 		over = filldir(dstbuf, dirent->name, dirent->namelen,
650e5e5558eSMiklos Szeredi 			       file->f_pos, dirent->ino, dirent->type);
651e5e5558eSMiklos Szeredi 		if (over)
652e5e5558eSMiklos Szeredi 			break;
653e5e5558eSMiklos Szeredi 
654e5e5558eSMiklos Szeredi 		buf += reclen;
655e5e5558eSMiklos Szeredi 		nbytes -= reclen;
656e5e5558eSMiklos Szeredi 		file->f_pos = dirent->off;
657e5e5558eSMiklos Szeredi 	}
658e5e5558eSMiklos Szeredi 
659e5e5558eSMiklos Szeredi 	return 0;
660e5e5558eSMiklos Szeredi }
661e5e5558eSMiklos Szeredi 
66204730fefSMiklos Szeredi static inline size_t fuse_send_readdir(struct fuse_req *req, struct file *file,
66304730fefSMiklos Szeredi 				       struct inode *inode, loff_t pos,
66404730fefSMiklos Szeredi 				       size_t count)
665e5e5558eSMiklos Szeredi {
66604730fefSMiklos Szeredi 	return fuse_send_read_common(req, file, inode, pos, count, 1);
667e5e5558eSMiklos Szeredi }
668e5e5558eSMiklos Szeredi 
669e5e5558eSMiklos Szeredi static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
670e5e5558eSMiklos Szeredi {
67104730fefSMiklos Szeredi 	int err;
67204730fefSMiklos Szeredi 	size_t nbytes;
67304730fefSMiklos Szeredi 	struct page *page;
67404730fefSMiklos Szeredi 	struct inode *inode = file->f_dentry->d_inode;
67504730fefSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
6767c352bdfSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
67704730fefSMiklos Szeredi 	if (!req)
67804730fefSMiklos Szeredi 		return -EINTR;
679e5e5558eSMiklos Szeredi 
68004730fefSMiklos Szeredi 	page = alloc_page(GFP_KERNEL);
68104730fefSMiklos Szeredi 	if (!page) {
68204730fefSMiklos Szeredi 		fuse_put_request(fc, req);
683e5e5558eSMiklos Szeredi 		return -ENOMEM;
68404730fefSMiklos Szeredi 	}
68504730fefSMiklos Szeredi 	req->num_pages = 1;
68604730fefSMiklos Szeredi 	req->pages[0] = page;
68704730fefSMiklos Szeredi 	nbytes = fuse_send_readdir(req, file, inode, file->f_pos, PAGE_SIZE);
68804730fefSMiklos Szeredi 	err = req->out.h.error;
68904730fefSMiklos Szeredi 	fuse_put_request(fc, req);
69004730fefSMiklos Szeredi 	if (!err)
69104730fefSMiklos Szeredi 		err = parse_dirfile(page_address(page), nbytes, file, dstbuf,
69204730fefSMiklos Szeredi 				    filldir);
693e5e5558eSMiklos Szeredi 
69404730fefSMiklos Szeredi 	__free_page(page);
695b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
69604730fefSMiklos Szeredi 	return err;
697e5e5558eSMiklos Szeredi }
698e5e5558eSMiklos Szeredi 
699e5e5558eSMiklos Szeredi static char *read_link(struct dentry *dentry)
700e5e5558eSMiklos Szeredi {
701e5e5558eSMiklos Szeredi 	struct inode *inode = dentry->d_inode;
702e5e5558eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
703e5e5558eSMiklos Szeredi 	struct fuse_req *req = fuse_get_request(fc);
704e5e5558eSMiklos Szeredi 	char *link;
705e5e5558eSMiklos Szeredi 
706e5e5558eSMiklos Szeredi 	if (!req)
7077c352bdfSMiklos Szeredi 		return ERR_PTR(-EINTR);
708e5e5558eSMiklos Szeredi 
709e5e5558eSMiklos Szeredi 	link = (char *) __get_free_page(GFP_KERNEL);
710e5e5558eSMiklos Szeredi 	if (!link) {
711e5e5558eSMiklos Szeredi 		link = ERR_PTR(-ENOMEM);
712e5e5558eSMiklos Szeredi 		goto out;
713e5e5558eSMiklos Szeredi 	}
714e5e5558eSMiklos Szeredi 	req->in.h.opcode = FUSE_READLINK;
715e5e5558eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
716e5e5558eSMiklos Szeredi 	req->inode = inode;
717e5e5558eSMiklos Szeredi 	req->out.argvar = 1;
718e5e5558eSMiklos Szeredi 	req->out.numargs = 1;
719e5e5558eSMiklos Szeredi 	req->out.args[0].size = PAGE_SIZE - 1;
720e5e5558eSMiklos Szeredi 	req->out.args[0].value = link;
721e5e5558eSMiklos Szeredi 	request_send(fc, req);
722e5e5558eSMiklos Szeredi 	if (req->out.h.error) {
723e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
724e5e5558eSMiklos Szeredi 		link = ERR_PTR(req->out.h.error);
725e5e5558eSMiklos Szeredi 	} else
726e5e5558eSMiklos Szeredi 		link[req->out.args[0].size] = '\0';
727e5e5558eSMiklos Szeredi  out:
728e5e5558eSMiklos Szeredi 	fuse_put_request(fc, req);
729b36c31baSMiklos Szeredi 	fuse_invalidate_attr(inode); /* atime changed */
730e5e5558eSMiklos Szeredi 	return link;
731e5e5558eSMiklos Szeredi }
732e5e5558eSMiklos Szeredi 
733e5e5558eSMiklos Szeredi static void free_link(char *link)
734e5e5558eSMiklos Szeredi {
735e5e5558eSMiklos Szeredi 	if (!IS_ERR(link))
736e5e5558eSMiklos Szeredi 		free_page((unsigned long) link);
737e5e5558eSMiklos Szeredi }
738e5e5558eSMiklos Szeredi 
739e5e5558eSMiklos Szeredi static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
740e5e5558eSMiklos Szeredi {
741e5e5558eSMiklos Szeredi 	nd_set_link(nd, read_link(dentry));
742e5e5558eSMiklos Szeredi 	return NULL;
743e5e5558eSMiklos Szeredi }
744e5e5558eSMiklos Szeredi 
745e5e5558eSMiklos Szeredi static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
746e5e5558eSMiklos Szeredi {
747e5e5558eSMiklos Szeredi 	free_link(nd_get_link(nd));
748e5e5558eSMiklos Szeredi }
749e5e5558eSMiklos Szeredi 
750e5e5558eSMiklos Szeredi static int fuse_dir_open(struct inode *inode, struct file *file)
751e5e5558eSMiklos Szeredi {
75204730fefSMiklos Szeredi 	return fuse_open_common(inode, file, 1);
753e5e5558eSMiklos Szeredi }
754e5e5558eSMiklos Szeredi 
755e5e5558eSMiklos Szeredi static int fuse_dir_release(struct inode *inode, struct file *file)
756e5e5558eSMiklos Szeredi {
75704730fefSMiklos Szeredi 	return fuse_release_common(inode, file, 1);
758e5e5558eSMiklos Szeredi }
759e5e5558eSMiklos Szeredi 
76082547981SMiklos Szeredi static int fuse_dir_fsync(struct file *file, struct dentry *de, int datasync)
76182547981SMiklos Szeredi {
76282547981SMiklos Szeredi 	/* nfsd can call this with no file */
76382547981SMiklos Szeredi 	return file ? fuse_fsync_common(file, de, datasync, 1) : 0;
76482547981SMiklos Szeredi }
76582547981SMiklos Szeredi 
7669e6268dbSMiklos Szeredi static unsigned iattr_to_fattr(struct iattr *iattr, struct fuse_attr *fattr)
7679e6268dbSMiklos Szeredi {
7689e6268dbSMiklos Szeredi 	unsigned ivalid = iattr->ia_valid;
7699e6268dbSMiklos Szeredi 	unsigned fvalid = 0;
7709e6268dbSMiklos Szeredi 
7719e6268dbSMiklos Szeredi 	memset(fattr, 0, sizeof(*fattr));
7729e6268dbSMiklos Szeredi 
7739e6268dbSMiklos Szeredi 	if (ivalid & ATTR_MODE)
7749e6268dbSMiklos Szeredi 		fvalid |= FATTR_MODE,   fattr->mode = iattr->ia_mode;
7759e6268dbSMiklos Szeredi 	if (ivalid & ATTR_UID)
7769e6268dbSMiklos Szeredi 		fvalid |= FATTR_UID,    fattr->uid = iattr->ia_uid;
7779e6268dbSMiklos Szeredi 	if (ivalid & ATTR_GID)
7789e6268dbSMiklos Szeredi 		fvalid |= FATTR_GID,    fattr->gid = iattr->ia_gid;
7799e6268dbSMiklos Szeredi 	if (ivalid & ATTR_SIZE)
7809e6268dbSMiklos Szeredi 		fvalid |= FATTR_SIZE,   fattr->size = iattr->ia_size;
7819e6268dbSMiklos Szeredi 	/* You can only _set_ these together (they may change by themselves) */
7829e6268dbSMiklos Szeredi 	if ((ivalid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) {
7839e6268dbSMiklos Szeredi 		fvalid |= FATTR_ATIME | FATTR_MTIME;
7849e6268dbSMiklos Szeredi 		fattr->atime = iattr->ia_atime.tv_sec;
7859e6268dbSMiklos Szeredi 		fattr->mtime = iattr->ia_mtime.tv_sec;
7869e6268dbSMiklos Szeredi 	}
7879e6268dbSMiklos Szeredi 
7889e6268dbSMiklos Szeredi 	return fvalid;
7899e6268dbSMiklos Szeredi }
7909e6268dbSMiklos Szeredi 
7919e6268dbSMiklos Szeredi static int fuse_setattr(struct dentry *entry, struct iattr *attr)
7929e6268dbSMiklos Szeredi {
7939e6268dbSMiklos Szeredi 	struct inode *inode = entry->d_inode;
7949e6268dbSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
7959e6268dbSMiklos Szeredi 	struct fuse_inode *fi = get_fuse_inode(inode);
7969e6268dbSMiklos Szeredi 	struct fuse_req *req;
7979e6268dbSMiklos Szeredi 	struct fuse_setattr_in inarg;
7989e6268dbSMiklos Szeredi 	struct fuse_attr_out outarg;
7999e6268dbSMiklos Szeredi 	int err;
8009e6268dbSMiklos Szeredi 	int is_truncate = 0;
8019e6268dbSMiklos Szeredi 
8021e9a4ed9SMiklos Szeredi 	if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
8031e9a4ed9SMiklos Szeredi 		err = inode_change_ok(inode, attr);
8041e9a4ed9SMiklos Szeredi 		if (err)
8051e9a4ed9SMiklos Szeredi 			return err;
8061e9a4ed9SMiklos Szeredi 	}
8071e9a4ed9SMiklos Szeredi 
8089e6268dbSMiklos Szeredi 	if (attr->ia_valid & ATTR_SIZE) {
8099e6268dbSMiklos Szeredi 		unsigned long limit;
8109e6268dbSMiklos Szeredi 		is_truncate = 1;
8119e6268dbSMiklos Szeredi 		limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur;
8129e6268dbSMiklos Szeredi 		if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) {
8139e6268dbSMiklos Szeredi 			send_sig(SIGXFSZ, current, 0);
8149e6268dbSMiklos Szeredi 			return -EFBIG;
8159e6268dbSMiklos Szeredi 		}
8169e6268dbSMiklos Szeredi 	}
8179e6268dbSMiklos Szeredi 
8189e6268dbSMiklos Szeredi 	req = fuse_get_request(fc);
8199e6268dbSMiklos Szeredi 	if (!req)
8207c352bdfSMiklos Szeredi 		return -EINTR;
8219e6268dbSMiklos Szeredi 
8229e6268dbSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
8239e6268dbSMiklos Szeredi 	inarg.valid = iattr_to_fattr(attr, &inarg.attr);
8249e6268dbSMiklos Szeredi 	req->in.h.opcode = FUSE_SETATTR;
8259e6268dbSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
8269e6268dbSMiklos Szeredi 	req->inode = inode;
8279e6268dbSMiklos Szeredi 	req->in.numargs = 1;
8289e6268dbSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
8299e6268dbSMiklos Szeredi 	req->in.args[0].value = &inarg;
8309e6268dbSMiklos Szeredi 	req->out.numargs = 1;
8319e6268dbSMiklos Szeredi 	req->out.args[0].size = sizeof(outarg);
8329e6268dbSMiklos Szeredi 	req->out.args[0].value = &outarg;
8339e6268dbSMiklos Szeredi 	request_send(fc, req);
8349e6268dbSMiklos Szeredi 	err = req->out.h.error;
8359e6268dbSMiklos Szeredi 	fuse_put_request(fc, req);
8369e6268dbSMiklos Szeredi 	if (!err) {
8379e6268dbSMiklos Szeredi 		if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
8389e6268dbSMiklos Szeredi 			make_bad_inode(inode);
8399e6268dbSMiklos Szeredi 			err = -EIO;
8409e6268dbSMiklos Szeredi 		} else {
8419e6268dbSMiklos Szeredi 			if (is_truncate) {
8429e6268dbSMiklos Szeredi 				loff_t origsize = i_size_read(inode);
8439e6268dbSMiklos Szeredi 				i_size_write(inode, outarg.attr.size);
8449e6268dbSMiklos Szeredi 				if (origsize > outarg.attr.size)
8459e6268dbSMiklos Szeredi 					vmtruncate(inode, outarg.attr.size);
8469e6268dbSMiklos Szeredi 			}
8479e6268dbSMiklos Szeredi 			fuse_change_attributes(inode, &outarg.attr);
8489e6268dbSMiklos Szeredi 			fi->i_time = time_to_jiffies(outarg.attr_valid,
8499e6268dbSMiklos Szeredi 						     outarg.attr_valid_nsec);
8509e6268dbSMiklos Szeredi 		}
8519e6268dbSMiklos Szeredi 	} else if (err == -EINTR)
8529e6268dbSMiklos Szeredi 		fuse_invalidate_attr(inode);
8539e6268dbSMiklos Szeredi 
8549e6268dbSMiklos Szeredi 	return err;
8559e6268dbSMiklos Szeredi }
8569e6268dbSMiklos Szeredi 
857e5e5558eSMiklos Szeredi static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
858e5e5558eSMiklos Szeredi 			struct kstat *stat)
859e5e5558eSMiklos Szeredi {
860e5e5558eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
861e5e5558eSMiklos Szeredi 	int err = fuse_revalidate(entry);
862e5e5558eSMiklos Szeredi 	if (!err)
863e5e5558eSMiklos Szeredi 		generic_fillattr(inode, stat);
864e5e5558eSMiklos Szeredi 
865e5e5558eSMiklos Szeredi 	return err;
866e5e5558eSMiklos Szeredi }
867e5e5558eSMiklos Szeredi 
868e5e5558eSMiklos Szeredi static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
869e5e5558eSMiklos Szeredi 				  struct nameidata *nd)
870e5e5558eSMiklos Szeredi {
871e5e5558eSMiklos Szeredi 	struct inode *inode;
872*fd72faacSMiklos Szeredi 	int err;
873*fd72faacSMiklos Szeredi 
874*fd72faacSMiklos Szeredi 	err = fuse_lookup_iget(dir, entry, &inode);
875e5e5558eSMiklos Szeredi 	if (err)
876e5e5558eSMiklos Szeredi 		return ERR_PTR(err);
877e5e5558eSMiklos Szeredi 	if (inode && S_ISDIR(inode->i_mode)) {
878e5e5558eSMiklos Szeredi 		/* Don't allow creating an alias to a directory  */
879e5e5558eSMiklos Szeredi 		struct dentry *alias = d_find_alias(inode);
880f12ec440SMiklos Szeredi 		if (alias) {
881e5e5558eSMiklos Szeredi 			dput(alias);
882e5e5558eSMiklos Szeredi 			iput(inode);
883e5e5558eSMiklos Szeredi 			return ERR_PTR(-EIO);
884e5e5558eSMiklos Szeredi 		}
885e5e5558eSMiklos Szeredi 	}
886f12ec440SMiklos Szeredi 	d_add(entry, inode);
887f12ec440SMiklos Szeredi 	return NULL;
888e5e5558eSMiklos Szeredi }
889e5e5558eSMiklos Szeredi 
89092a8780eSMiklos Szeredi static int fuse_setxattr(struct dentry *entry, const char *name,
89192a8780eSMiklos Szeredi 			 const void *value, size_t size, int flags)
89292a8780eSMiklos Szeredi {
89392a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
89492a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
89592a8780eSMiklos Szeredi 	struct fuse_req *req;
89692a8780eSMiklos Szeredi 	struct fuse_setxattr_in inarg;
89792a8780eSMiklos Szeredi 	int err;
89892a8780eSMiklos Szeredi 
89992a8780eSMiklos Szeredi 	if (size > FUSE_XATTR_SIZE_MAX)
90092a8780eSMiklos Szeredi 		return -E2BIG;
90192a8780eSMiklos Szeredi 
90292a8780eSMiklos Szeredi 	if (fc->no_setxattr)
90392a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
90492a8780eSMiklos Szeredi 
90592a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
90692a8780eSMiklos Szeredi 	if (!req)
9077c352bdfSMiklos Szeredi 		return -EINTR;
90892a8780eSMiklos Szeredi 
90992a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
91092a8780eSMiklos Szeredi 	inarg.size = size;
91192a8780eSMiklos Szeredi 	inarg.flags = flags;
91292a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_SETXATTR;
91392a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
91492a8780eSMiklos Szeredi 	req->inode = inode;
91592a8780eSMiklos Szeredi 	req->in.numargs = 3;
91692a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
91792a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
91892a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
91992a8780eSMiklos Szeredi 	req->in.args[1].value = name;
92092a8780eSMiklos Szeredi 	req->in.args[2].size = size;
92192a8780eSMiklos Szeredi 	req->in.args[2].value = value;
92292a8780eSMiklos Szeredi 	request_send(fc, req);
92392a8780eSMiklos Szeredi 	err = req->out.h.error;
92492a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
92592a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
92692a8780eSMiklos Szeredi 		fc->no_setxattr = 1;
92792a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
92892a8780eSMiklos Szeredi 	}
92992a8780eSMiklos Szeredi 	return err;
93092a8780eSMiklos Szeredi }
93192a8780eSMiklos Szeredi 
93292a8780eSMiklos Szeredi static ssize_t fuse_getxattr(struct dentry *entry, const char *name,
93392a8780eSMiklos Szeredi 			     void *value, size_t size)
93492a8780eSMiklos Szeredi {
93592a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
93692a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
93792a8780eSMiklos Szeredi 	struct fuse_req *req;
93892a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
93992a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
94092a8780eSMiklos Szeredi 	ssize_t ret;
94192a8780eSMiklos Szeredi 
94292a8780eSMiklos Szeredi 	if (fc->no_getxattr)
94392a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
94492a8780eSMiklos Szeredi 
94592a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
94692a8780eSMiklos Szeredi 	if (!req)
9477c352bdfSMiklos Szeredi 		return -EINTR;
94892a8780eSMiklos Szeredi 
94992a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
95092a8780eSMiklos Szeredi 	inarg.size = size;
95192a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_GETXATTR;
95292a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
95392a8780eSMiklos Szeredi 	req->inode = inode;
95492a8780eSMiklos Szeredi 	req->in.numargs = 2;
95592a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
95692a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
95792a8780eSMiklos Szeredi 	req->in.args[1].size = strlen(name) + 1;
95892a8780eSMiklos Szeredi 	req->in.args[1].value = name;
95992a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
96092a8780eSMiklos Szeredi 	req->out.numargs = 1;
96192a8780eSMiklos Szeredi 	if (size) {
96292a8780eSMiklos Szeredi 		req->out.argvar = 1;
96392a8780eSMiklos Szeredi 		req->out.args[0].size = size;
96492a8780eSMiklos Szeredi 		req->out.args[0].value = value;
96592a8780eSMiklos Szeredi 	} else {
96692a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
96792a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
96892a8780eSMiklos Szeredi 	}
96992a8780eSMiklos Szeredi 	request_send(fc, req);
97092a8780eSMiklos Szeredi 	ret = req->out.h.error;
97192a8780eSMiklos Szeredi 	if (!ret)
97292a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
97392a8780eSMiklos Szeredi 	else {
97492a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
97592a8780eSMiklos Szeredi 			fc->no_getxattr = 1;
97692a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
97792a8780eSMiklos Szeredi 		}
97892a8780eSMiklos Szeredi 	}
97992a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
98092a8780eSMiklos Szeredi 	return ret;
98192a8780eSMiklos Szeredi }
98292a8780eSMiklos Szeredi 
98392a8780eSMiklos Szeredi static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size)
98492a8780eSMiklos Szeredi {
98592a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
98692a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
98792a8780eSMiklos Szeredi 	struct fuse_req *req;
98892a8780eSMiklos Szeredi 	struct fuse_getxattr_in inarg;
98992a8780eSMiklos Szeredi 	struct fuse_getxattr_out outarg;
99092a8780eSMiklos Szeredi 	ssize_t ret;
99192a8780eSMiklos Szeredi 
99292a8780eSMiklos Szeredi 	if (fc->no_listxattr)
99392a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
99492a8780eSMiklos Szeredi 
99592a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
99692a8780eSMiklos Szeredi 	if (!req)
9977c352bdfSMiklos Szeredi 		return -EINTR;
99892a8780eSMiklos Szeredi 
99992a8780eSMiklos Szeredi 	memset(&inarg, 0, sizeof(inarg));
100092a8780eSMiklos Szeredi 	inarg.size = size;
100192a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_LISTXATTR;
100292a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
100392a8780eSMiklos Szeredi 	req->inode = inode;
100492a8780eSMiklos Szeredi 	req->in.numargs = 1;
100592a8780eSMiklos Szeredi 	req->in.args[0].size = sizeof(inarg);
100692a8780eSMiklos Szeredi 	req->in.args[0].value = &inarg;
100792a8780eSMiklos Szeredi 	/* This is really two different operations rolled into one */
100892a8780eSMiklos Szeredi 	req->out.numargs = 1;
100992a8780eSMiklos Szeredi 	if (size) {
101092a8780eSMiklos Szeredi 		req->out.argvar = 1;
101192a8780eSMiklos Szeredi 		req->out.args[0].size = size;
101292a8780eSMiklos Szeredi 		req->out.args[0].value = list;
101392a8780eSMiklos Szeredi 	} else {
101492a8780eSMiklos Szeredi 		req->out.args[0].size = sizeof(outarg);
101592a8780eSMiklos Szeredi 		req->out.args[0].value = &outarg;
101692a8780eSMiklos Szeredi 	}
101792a8780eSMiklos Szeredi 	request_send(fc, req);
101892a8780eSMiklos Szeredi 	ret = req->out.h.error;
101992a8780eSMiklos Szeredi 	if (!ret)
102092a8780eSMiklos Szeredi 		ret = size ? req->out.args[0].size : outarg.size;
102192a8780eSMiklos Szeredi 	else {
102292a8780eSMiklos Szeredi 		if (ret == -ENOSYS) {
102392a8780eSMiklos Szeredi 			fc->no_listxattr = 1;
102492a8780eSMiklos Szeredi 			ret = -EOPNOTSUPP;
102592a8780eSMiklos Szeredi 		}
102692a8780eSMiklos Szeredi 	}
102792a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
102892a8780eSMiklos Szeredi 	return ret;
102992a8780eSMiklos Szeredi }
103092a8780eSMiklos Szeredi 
103192a8780eSMiklos Szeredi static int fuse_removexattr(struct dentry *entry, const char *name)
103292a8780eSMiklos Szeredi {
103392a8780eSMiklos Szeredi 	struct inode *inode = entry->d_inode;
103492a8780eSMiklos Szeredi 	struct fuse_conn *fc = get_fuse_conn(inode);
103592a8780eSMiklos Szeredi 	struct fuse_req *req;
103692a8780eSMiklos Szeredi 	int err;
103792a8780eSMiklos Szeredi 
103892a8780eSMiklos Szeredi 	if (fc->no_removexattr)
103992a8780eSMiklos Szeredi 		return -EOPNOTSUPP;
104092a8780eSMiklos Szeredi 
104192a8780eSMiklos Szeredi 	req = fuse_get_request(fc);
104292a8780eSMiklos Szeredi 	if (!req)
10437c352bdfSMiklos Szeredi 		return -EINTR;
104492a8780eSMiklos Szeredi 
104592a8780eSMiklos Szeredi 	req->in.h.opcode = FUSE_REMOVEXATTR;
104692a8780eSMiklos Szeredi 	req->in.h.nodeid = get_node_id(inode);
104792a8780eSMiklos Szeredi 	req->inode = inode;
104892a8780eSMiklos Szeredi 	req->in.numargs = 1;
104992a8780eSMiklos Szeredi 	req->in.args[0].size = strlen(name) + 1;
105092a8780eSMiklos Szeredi 	req->in.args[0].value = name;
105192a8780eSMiklos Szeredi 	request_send(fc, req);
105292a8780eSMiklos Szeredi 	err = req->out.h.error;
105392a8780eSMiklos Szeredi 	fuse_put_request(fc, req);
105492a8780eSMiklos Szeredi 	if (err == -ENOSYS) {
105592a8780eSMiklos Szeredi 		fc->no_removexattr = 1;
105692a8780eSMiklos Szeredi 		err = -EOPNOTSUPP;
105792a8780eSMiklos Szeredi 	}
105892a8780eSMiklos Szeredi 	return err;
105992a8780eSMiklos Szeredi }
106092a8780eSMiklos Szeredi 
1061e5e5558eSMiklos Szeredi static struct inode_operations fuse_dir_inode_operations = {
1062e5e5558eSMiklos Szeredi 	.lookup		= fuse_lookup,
10639e6268dbSMiklos Szeredi 	.mkdir		= fuse_mkdir,
10649e6268dbSMiklos Szeredi 	.symlink	= fuse_symlink,
10659e6268dbSMiklos Szeredi 	.unlink		= fuse_unlink,
10669e6268dbSMiklos Szeredi 	.rmdir		= fuse_rmdir,
10679e6268dbSMiklos Szeredi 	.rename		= fuse_rename,
10689e6268dbSMiklos Szeredi 	.link		= fuse_link,
10699e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
10709e6268dbSMiklos Szeredi 	.create		= fuse_create,
10719e6268dbSMiklos Szeredi 	.mknod		= fuse_mknod,
1072e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1073e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
107492a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
107592a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
107692a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
107792a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1078e5e5558eSMiklos Szeredi };
1079e5e5558eSMiklos Szeredi 
1080e5e5558eSMiklos Szeredi static struct file_operations fuse_dir_operations = {
1081b6aeadedSMiklos Szeredi 	.llseek		= generic_file_llseek,
1082e5e5558eSMiklos Szeredi 	.read		= generic_read_dir,
1083e5e5558eSMiklos Szeredi 	.readdir	= fuse_readdir,
1084e5e5558eSMiklos Szeredi 	.open		= fuse_dir_open,
1085e5e5558eSMiklos Szeredi 	.release	= fuse_dir_release,
108682547981SMiklos Szeredi 	.fsync		= fuse_dir_fsync,
1087e5e5558eSMiklos Szeredi };
1088e5e5558eSMiklos Szeredi 
1089e5e5558eSMiklos Szeredi static struct inode_operations fuse_common_inode_operations = {
10909e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1091e5e5558eSMiklos Szeredi 	.permission	= fuse_permission,
1092e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
109392a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
109492a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
109592a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
109692a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1097e5e5558eSMiklos Szeredi };
1098e5e5558eSMiklos Szeredi 
1099e5e5558eSMiklos Szeredi static struct inode_operations fuse_symlink_inode_operations = {
11009e6268dbSMiklos Szeredi 	.setattr	= fuse_setattr,
1101e5e5558eSMiklos Szeredi 	.follow_link	= fuse_follow_link,
1102e5e5558eSMiklos Szeredi 	.put_link	= fuse_put_link,
1103e5e5558eSMiklos Szeredi 	.readlink	= generic_readlink,
1104e5e5558eSMiklos Szeredi 	.getattr	= fuse_getattr,
110592a8780eSMiklos Szeredi 	.setxattr	= fuse_setxattr,
110692a8780eSMiklos Szeredi 	.getxattr	= fuse_getxattr,
110792a8780eSMiklos Szeredi 	.listxattr	= fuse_listxattr,
110892a8780eSMiklos Szeredi 	.removexattr	= fuse_removexattr,
1109e5e5558eSMiklos Szeredi };
1110e5e5558eSMiklos Szeredi 
1111e5e5558eSMiklos Szeredi void fuse_init_common(struct inode *inode)
1112e5e5558eSMiklos Szeredi {
1113e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_common_inode_operations;
1114e5e5558eSMiklos Szeredi }
1115e5e5558eSMiklos Szeredi 
1116e5e5558eSMiklos Szeredi void fuse_init_dir(struct inode *inode)
1117e5e5558eSMiklos Szeredi {
1118e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_dir_inode_operations;
1119e5e5558eSMiklos Szeredi 	inode->i_fop = &fuse_dir_operations;
1120e5e5558eSMiklos Szeredi }
1121e5e5558eSMiklos Szeredi 
1122e5e5558eSMiklos Szeredi void fuse_init_symlink(struct inode *inode)
1123e5e5558eSMiklos Szeredi {
1124e5e5558eSMiklos Szeredi 	inode->i_op = &fuse_symlink_inode_operations;
1125e5e5558eSMiklos Szeredi }
1126