xref: /aosp_15_r20/external/libfuse/lib/modules/subdir.c (revision 9e5649576b786774a32d7b0252c9cd8c6538fa49)
1*9e564957SAndroid Build Coastguard Worker /*
2*9e564957SAndroid Build Coastguard Worker   fuse subdir module: offset paths with a base directory
3*9e564957SAndroid Build Coastguard Worker   Copyright (C) 2007  Miklos Szeredi <[email protected]>
4*9e564957SAndroid Build Coastguard Worker 
5*9e564957SAndroid Build Coastguard Worker   This program can be distributed under the terms of the GNU LGPLv2.
6*9e564957SAndroid Build Coastguard Worker   See the file COPYING.LIB
7*9e564957SAndroid Build Coastguard Worker */
8*9e564957SAndroid Build Coastguard Worker 
9*9e564957SAndroid Build Coastguard Worker #include <fuse_config.h>
10*9e564957SAndroid Build Coastguard Worker 
11*9e564957SAndroid Build Coastguard Worker #include <fuse.h>
12*9e564957SAndroid Build Coastguard Worker #include <stdio.h>
13*9e564957SAndroid Build Coastguard Worker #include <stdlib.h>
14*9e564957SAndroid Build Coastguard Worker #include <stddef.h>
15*9e564957SAndroid Build Coastguard Worker #include <string.h>
16*9e564957SAndroid Build Coastguard Worker #include <errno.h>
17*9e564957SAndroid Build Coastguard Worker 
18*9e564957SAndroid Build Coastguard Worker struct subdir {
19*9e564957SAndroid Build Coastguard Worker 	char *base;
20*9e564957SAndroid Build Coastguard Worker 	size_t baselen;
21*9e564957SAndroid Build Coastguard Worker 	int rellinks;
22*9e564957SAndroid Build Coastguard Worker 	struct fuse_fs *next;
23*9e564957SAndroid Build Coastguard Worker };
24*9e564957SAndroid Build Coastguard Worker 
subdir_get(void)25*9e564957SAndroid Build Coastguard Worker static struct subdir *subdir_get(void)
26*9e564957SAndroid Build Coastguard Worker {
27*9e564957SAndroid Build Coastguard Worker 	return fuse_get_context()->private_data;
28*9e564957SAndroid Build Coastguard Worker }
29*9e564957SAndroid Build Coastguard Worker 
subdir_addpath(struct subdir * d,const char * path,char ** newpathp)30*9e564957SAndroid Build Coastguard Worker static int subdir_addpath(struct subdir *d, const char *path, char **newpathp)
31*9e564957SAndroid Build Coastguard Worker {
32*9e564957SAndroid Build Coastguard Worker 	char *newpath = NULL;
33*9e564957SAndroid Build Coastguard Worker 
34*9e564957SAndroid Build Coastguard Worker 	if (path != NULL) {
35*9e564957SAndroid Build Coastguard Worker 		unsigned newlen = d->baselen + strlen(path);
36*9e564957SAndroid Build Coastguard Worker 
37*9e564957SAndroid Build Coastguard Worker 		newpath = malloc(newlen + 2);
38*9e564957SAndroid Build Coastguard Worker 		if (!newpath)
39*9e564957SAndroid Build Coastguard Worker 			return -ENOMEM;
40*9e564957SAndroid Build Coastguard Worker 
41*9e564957SAndroid Build Coastguard Worker 		if (path[0] == '/')
42*9e564957SAndroid Build Coastguard Worker 			path++;
43*9e564957SAndroid Build Coastguard Worker 		strcpy(newpath, d->base);
44*9e564957SAndroid Build Coastguard Worker 		strcpy(newpath + d->baselen, path);
45*9e564957SAndroid Build Coastguard Worker 		if (!newpath[0])
46*9e564957SAndroid Build Coastguard Worker 			strcpy(newpath, ".");
47*9e564957SAndroid Build Coastguard Worker 	}
48*9e564957SAndroid Build Coastguard Worker 	*newpathp = newpath;
49*9e564957SAndroid Build Coastguard Worker 
50*9e564957SAndroid Build Coastguard Worker 	return 0;
51*9e564957SAndroid Build Coastguard Worker }
52*9e564957SAndroid Build Coastguard Worker 
subdir_getattr(const char * path,struct stat * stbuf,struct fuse_file_info * fi)53*9e564957SAndroid Build Coastguard Worker static int subdir_getattr(const char *path, struct stat *stbuf,
54*9e564957SAndroid Build Coastguard Worker 			  struct fuse_file_info *fi)
55*9e564957SAndroid Build Coastguard Worker {
56*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
57*9e564957SAndroid Build Coastguard Worker 	char *newpath;
58*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
59*9e564957SAndroid Build Coastguard Worker 	if (!err) {
60*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_getattr(d->next, newpath, stbuf, fi);
61*9e564957SAndroid Build Coastguard Worker 		free(newpath);
62*9e564957SAndroid Build Coastguard Worker 	}
63*9e564957SAndroid Build Coastguard Worker 	return err;
64*9e564957SAndroid Build Coastguard Worker }
65*9e564957SAndroid Build Coastguard Worker 
subdir_access(const char * path,int mask)66*9e564957SAndroid Build Coastguard Worker static int subdir_access(const char *path, int mask)
67*9e564957SAndroid Build Coastguard Worker {
68*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
69*9e564957SAndroid Build Coastguard Worker 	char *newpath;
70*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
71*9e564957SAndroid Build Coastguard Worker 	if (!err) {
72*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_access(d->next, newpath, mask);
73*9e564957SAndroid Build Coastguard Worker 		free(newpath);
74*9e564957SAndroid Build Coastguard Worker 	}
75*9e564957SAndroid Build Coastguard Worker 	return err;
76*9e564957SAndroid Build Coastguard Worker }
77*9e564957SAndroid Build Coastguard Worker 
78*9e564957SAndroid Build Coastguard Worker 
count_components(const char * p)79*9e564957SAndroid Build Coastguard Worker static int count_components(const char *p)
80*9e564957SAndroid Build Coastguard Worker {
81*9e564957SAndroid Build Coastguard Worker 	int ctr;
82*9e564957SAndroid Build Coastguard Worker 
83*9e564957SAndroid Build Coastguard Worker 	for (; *p == '/'; p++);
84*9e564957SAndroid Build Coastguard Worker 	for (ctr = 0; *p; ctr++) {
85*9e564957SAndroid Build Coastguard Worker 		for (; *p && *p != '/'; p++);
86*9e564957SAndroid Build Coastguard Worker 		for (; *p == '/'; p++);
87*9e564957SAndroid Build Coastguard Worker 	}
88*9e564957SAndroid Build Coastguard Worker 	return ctr;
89*9e564957SAndroid Build Coastguard Worker }
90*9e564957SAndroid Build Coastguard Worker 
strip_common(const char ** sp,const char ** tp)91*9e564957SAndroid Build Coastguard Worker static void strip_common(const char **sp, const char **tp)
92*9e564957SAndroid Build Coastguard Worker {
93*9e564957SAndroid Build Coastguard Worker 	const char *s = *sp;
94*9e564957SAndroid Build Coastguard Worker 	const char *t = *tp;
95*9e564957SAndroid Build Coastguard Worker 	do {
96*9e564957SAndroid Build Coastguard Worker 		for (; *s == '/'; s++);
97*9e564957SAndroid Build Coastguard Worker 		for (; *t == '/'; t++);
98*9e564957SAndroid Build Coastguard Worker 		*tp = t;
99*9e564957SAndroid Build Coastguard Worker 		*sp = s;
100*9e564957SAndroid Build Coastguard Worker 		for (; *s == *t && *s && *s != '/'; s++, t++);
101*9e564957SAndroid Build Coastguard Worker 	} while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t));
102*9e564957SAndroid Build Coastguard Worker }
103*9e564957SAndroid Build Coastguard Worker 
transform_symlink(struct subdir * d,const char * path,char * buf,size_t size)104*9e564957SAndroid Build Coastguard Worker static void transform_symlink(struct subdir *d, const char *path,
105*9e564957SAndroid Build Coastguard Worker 			      char *buf, size_t size)
106*9e564957SAndroid Build Coastguard Worker {
107*9e564957SAndroid Build Coastguard Worker 	const char *l = buf;
108*9e564957SAndroid Build Coastguard Worker 	size_t llen;
109*9e564957SAndroid Build Coastguard Worker 	char *s;
110*9e564957SAndroid Build Coastguard Worker 	int dotdots;
111*9e564957SAndroid Build Coastguard Worker 	int i;
112*9e564957SAndroid Build Coastguard Worker 
113*9e564957SAndroid Build Coastguard Worker 	if (l[0] != '/' || d->base[0] != '/')
114*9e564957SAndroid Build Coastguard Worker 		return;
115*9e564957SAndroid Build Coastguard Worker 
116*9e564957SAndroid Build Coastguard Worker 	strip_common(&l, &path);
117*9e564957SAndroid Build Coastguard Worker 	if (l - buf < (long) d->baselen)
118*9e564957SAndroid Build Coastguard Worker 		return;
119*9e564957SAndroid Build Coastguard Worker 
120*9e564957SAndroid Build Coastguard Worker 	dotdots = count_components(path);
121*9e564957SAndroid Build Coastguard Worker 	if (!dotdots)
122*9e564957SAndroid Build Coastguard Worker 		return;
123*9e564957SAndroid Build Coastguard Worker 	dotdots--;
124*9e564957SAndroid Build Coastguard Worker 
125*9e564957SAndroid Build Coastguard Worker 	llen = strlen(l);
126*9e564957SAndroid Build Coastguard Worker 	if (dotdots * 3 + llen + 2 > size)
127*9e564957SAndroid Build Coastguard Worker 		return;
128*9e564957SAndroid Build Coastguard Worker 
129*9e564957SAndroid Build Coastguard Worker 	s = buf + dotdots * 3;
130*9e564957SAndroid Build Coastguard Worker 	if (llen)
131*9e564957SAndroid Build Coastguard Worker 		memmove(s, l, llen + 1);
132*9e564957SAndroid Build Coastguard Worker 	else if (!dotdots)
133*9e564957SAndroid Build Coastguard Worker 		strcpy(s, ".");
134*9e564957SAndroid Build Coastguard Worker 	else
135*9e564957SAndroid Build Coastguard Worker 		*s = '\0';
136*9e564957SAndroid Build Coastguard Worker 
137*9e564957SAndroid Build Coastguard Worker 	for (s = buf, i = 0; i < dotdots; i++, s += 3)
138*9e564957SAndroid Build Coastguard Worker 		memcpy(s, "../", 3);
139*9e564957SAndroid Build Coastguard Worker }
140*9e564957SAndroid Build Coastguard Worker 
141*9e564957SAndroid Build Coastguard Worker 
subdir_readlink(const char * path,char * buf,size_t size)142*9e564957SAndroid Build Coastguard Worker static int subdir_readlink(const char *path, char *buf, size_t size)
143*9e564957SAndroid Build Coastguard Worker {
144*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
145*9e564957SAndroid Build Coastguard Worker 	char *newpath;
146*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
147*9e564957SAndroid Build Coastguard Worker 	if (!err) {
148*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_readlink(d->next, newpath, buf, size);
149*9e564957SAndroid Build Coastguard Worker 		if (!err && d->rellinks)
150*9e564957SAndroid Build Coastguard Worker 			transform_symlink(d, newpath, buf, size);
151*9e564957SAndroid Build Coastguard Worker 		free(newpath);
152*9e564957SAndroid Build Coastguard Worker 	}
153*9e564957SAndroid Build Coastguard Worker 	return err;
154*9e564957SAndroid Build Coastguard Worker }
155*9e564957SAndroid Build Coastguard Worker 
subdir_opendir(const char * path,struct fuse_file_info * fi)156*9e564957SAndroid Build Coastguard Worker static int subdir_opendir(const char *path, struct fuse_file_info *fi)
157*9e564957SAndroid Build Coastguard Worker {
158*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
159*9e564957SAndroid Build Coastguard Worker 	char *newpath;
160*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
161*9e564957SAndroid Build Coastguard Worker 	if (!err) {
162*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_opendir(d->next, newpath, fi);
163*9e564957SAndroid Build Coastguard Worker 		free(newpath);
164*9e564957SAndroid Build Coastguard Worker 	}
165*9e564957SAndroid Build Coastguard Worker 	return err;
166*9e564957SAndroid Build Coastguard Worker }
167*9e564957SAndroid Build Coastguard Worker 
subdir_readdir(const char * path,void * buf,fuse_fill_dir_t filler,off_t offset,struct fuse_file_info * fi,enum fuse_readdir_flags flags)168*9e564957SAndroid Build Coastguard Worker static int subdir_readdir(const char *path, void *buf,
169*9e564957SAndroid Build Coastguard Worker 			  fuse_fill_dir_t filler, off_t offset,
170*9e564957SAndroid Build Coastguard Worker 			  struct fuse_file_info *fi,
171*9e564957SAndroid Build Coastguard Worker 			  enum fuse_readdir_flags flags)
172*9e564957SAndroid Build Coastguard Worker {
173*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
174*9e564957SAndroid Build Coastguard Worker 	char *newpath;
175*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
176*9e564957SAndroid Build Coastguard Worker 	if (!err) {
177*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_readdir(d->next, newpath, buf, filler, offset,
178*9e564957SAndroid Build Coastguard Worker 				      fi, flags);
179*9e564957SAndroid Build Coastguard Worker 		free(newpath);
180*9e564957SAndroid Build Coastguard Worker 	}
181*9e564957SAndroid Build Coastguard Worker 	return err;
182*9e564957SAndroid Build Coastguard Worker }
183*9e564957SAndroid Build Coastguard Worker 
subdir_releasedir(const char * path,struct fuse_file_info * fi)184*9e564957SAndroid Build Coastguard Worker static int subdir_releasedir(const char *path, struct fuse_file_info *fi)
185*9e564957SAndroid Build Coastguard Worker {
186*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
187*9e564957SAndroid Build Coastguard Worker 	char *newpath;
188*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
189*9e564957SAndroid Build Coastguard Worker 	if (!err) {
190*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_releasedir(d->next, newpath, fi);
191*9e564957SAndroid Build Coastguard Worker 		free(newpath);
192*9e564957SAndroid Build Coastguard Worker 	}
193*9e564957SAndroid Build Coastguard Worker 	return err;
194*9e564957SAndroid Build Coastguard Worker }
195*9e564957SAndroid Build Coastguard Worker 
subdir_mknod(const char * path,mode_t mode,dev_t rdev)196*9e564957SAndroid Build Coastguard Worker static int subdir_mknod(const char *path, mode_t mode, dev_t rdev)
197*9e564957SAndroid Build Coastguard Worker {
198*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
199*9e564957SAndroid Build Coastguard Worker 	char *newpath;
200*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
201*9e564957SAndroid Build Coastguard Worker 	if (!err) {
202*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_mknod(d->next, newpath, mode, rdev);
203*9e564957SAndroid Build Coastguard Worker 		free(newpath);
204*9e564957SAndroid Build Coastguard Worker 	}
205*9e564957SAndroid Build Coastguard Worker 	return err;
206*9e564957SAndroid Build Coastguard Worker }
207*9e564957SAndroid Build Coastguard Worker 
subdir_mkdir(const char * path,mode_t mode)208*9e564957SAndroid Build Coastguard Worker static int subdir_mkdir(const char *path, mode_t mode)
209*9e564957SAndroid Build Coastguard Worker {
210*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
211*9e564957SAndroid Build Coastguard Worker 	char *newpath;
212*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
213*9e564957SAndroid Build Coastguard Worker 	if (!err) {
214*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_mkdir(d->next, newpath, mode);
215*9e564957SAndroid Build Coastguard Worker 		free(newpath);
216*9e564957SAndroid Build Coastguard Worker 	}
217*9e564957SAndroid Build Coastguard Worker 	return err;
218*9e564957SAndroid Build Coastguard Worker }
219*9e564957SAndroid Build Coastguard Worker 
subdir_unlink(const char * path)220*9e564957SAndroid Build Coastguard Worker static int subdir_unlink(const char *path)
221*9e564957SAndroid Build Coastguard Worker {
222*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
223*9e564957SAndroid Build Coastguard Worker 	char *newpath;
224*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
225*9e564957SAndroid Build Coastguard Worker 	if (!err) {
226*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_unlink(d->next, newpath);
227*9e564957SAndroid Build Coastguard Worker 		free(newpath);
228*9e564957SAndroid Build Coastguard Worker 	}
229*9e564957SAndroid Build Coastguard Worker 	return err;
230*9e564957SAndroid Build Coastguard Worker }
231*9e564957SAndroid Build Coastguard Worker 
subdir_rmdir(const char * path)232*9e564957SAndroid Build Coastguard Worker static int subdir_rmdir(const char *path)
233*9e564957SAndroid Build Coastguard Worker {
234*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
235*9e564957SAndroid Build Coastguard Worker 	char *newpath;
236*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
237*9e564957SAndroid Build Coastguard Worker 	if (!err) {
238*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_rmdir(d->next, newpath);
239*9e564957SAndroid Build Coastguard Worker 		free(newpath);
240*9e564957SAndroid Build Coastguard Worker 	}
241*9e564957SAndroid Build Coastguard Worker 	return err;
242*9e564957SAndroid Build Coastguard Worker }
243*9e564957SAndroid Build Coastguard Worker 
subdir_symlink(const char * from,const char * path)244*9e564957SAndroid Build Coastguard Worker static int subdir_symlink(const char *from, const char *path)
245*9e564957SAndroid Build Coastguard Worker {
246*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
247*9e564957SAndroid Build Coastguard Worker 	char *newpath;
248*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
249*9e564957SAndroid Build Coastguard Worker 	if (!err) {
250*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_symlink(d->next, from, newpath);
251*9e564957SAndroid Build Coastguard Worker 		free(newpath);
252*9e564957SAndroid Build Coastguard Worker 	}
253*9e564957SAndroid Build Coastguard Worker 	return err;
254*9e564957SAndroid Build Coastguard Worker }
255*9e564957SAndroid Build Coastguard Worker 
subdir_rename(const char * from,const char * to,unsigned int flags)256*9e564957SAndroid Build Coastguard Worker static int subdir_rename(const char *from, const char *to, unsigned int flags)
257*9e564957SAndroid Build Coastguard Worker {
258*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
259*9e564957SAndroid Build Coastguard Worker 	char *newfrom;
260*9e564957SAndroid Build Coastguard Worker 	char *newto;
261*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, from, &newfrom);
262*9e564957SAndroid Build Coastguard Worker 	if (!err) {
263*9e564957SAndroid Build Coastguard Worker 		err = subdir_addpath(d, to, &newto);
264*9e564957SAndroid Build Coastguard Worker 		if (!err) {
265*9e564957SAndroid Build Coastguard Worker 			err = fuse_fs_rename(d->next, newfrom, newto, flags);
266*9e564957SAndroid Build Coastguard Worker 			free(newto);
267*9e564957SAndroid Build Coastguard Worker 		}
268*9e564957SAndroid Build Coastguard Worker 		free(newfrom);
269*9e564957SAndroid Build Coastguard Worker 	}
270*9e564957SAndroid Build Coastguard Worker 	return err;
271*9e564957SAndroid Build Coastguard Worker }
272*9e564957SAndroid Build Coastguard Worker 
subdir_link(const char * from,const char * to)273*9e564957SAndroid Build Coastguard Worker static int subdir_link(const char *from, const char *to)
274*9e564957SAndroid Build Coastguard Worker {
275*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
276*9e564957SAndroid Build Coastguard Worker 	char *newfrom;
277*9e564957SAndroid Build Coastguard Worker 	char *newto;
278*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, from, &newfrom);
279*9e564957SAndroid Build Coastguard Worker 	if (!err) {
280*9e564957SAndroid Build Coastguard Worker 		err = subdir_addpath(d, to, &newto);
281*9e564957SAndroid Build Coastguard Worker 		if (!err) {
282*9e564957SAndroid Build Coastguard Worker 			err = fuse_fs_link(d->next, newfrom, newto);
283*9e564957SAndroid Build Coastguard Worker 			free(newto);
284*9e564957SAndroid Build Coastguard Worker 		}
285*9e564957SAndroid Build Coastguard Worker 		free(newfrom);
286*9e564957SAndroid Build Coastguard Worker 	}
287*9e564957SAndroid Build Coastguard Worker 	return err;
288*9e564957SAndroid Build Coastguard Worker }
289*9e564957SAndroid Build Coastguard Worker 
subdir_chmod(const char * path,mode_t mode,struct fuse_file_info * fi)290*9e564957SAndroid Build Coastguard Worker static int subdir_chmod(const char *path, mode_t mode,
291*9e564957SAndroid Build Coastguard Worker 			struct fuse_file_info *fi)
292*9e564957SAndroid Build Coastguard Worker {
293*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
294*9e564957SAndroid Build Coastguard Worker 	char *newpath;
295*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
296*9e564957SAndroid Build Coastguard Worker 	if (!err) {
297*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_chmod(d->next, newpath, mode, fi);
298*9e564957SAndroid Build Coastguard Worker 		free(newpath);
299*9e564957SAndroid Build Coastguard Worker 	}
300*9e564957SAndroid Build Coastguard Worker 	return err;
301*9e564957SAndroid Build Coastguard Worker }
302*9e564957SAndroid Build Coastguard Worker 
subdir_chown(const char * path,uid_t uid,gid_t gid,struct fuse_file_info * fi)303*9e564957SAndroid Build Coastguard Worker static int subdir_chown(const char *path, uid_t uid, gid_t gid,
304*9e564957SAndroid Build Coastguard Worker 			struct fuse_file_info *fi)
305*9e564957SAndroid Build Coastguard Worker {
306*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
307*9e564957SAndroid Build Coastguard Worker 	char *newpath;
308*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
309*9e564957SAndroid Build Coastguard Worker 	if (!err) {
310*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_chown(d->next, newpath, uid, gid, fi);
311*9e564957SAndroid Build Coastguard Worker 		free(newpath);
312*9e564957SAndroid Build Coastguard Worker 	}
313*9e564957SAndroid Build Coastguard Worker 	return err;
314*9e564957SAndroid Build Coastguard Worker }
315*9e564957SAndroid Build Coastguard Worker 
subdir_truncate(const char * path,off_t size,struct fuse_file_info * fi)316*9e564957SAndroid Build Coastguard Worker static int subdir_truncate(const char *path, off_t size,
317*9e564957SAndroid Build Coastguard Worker 			   struct fuse_file_info *fi)
318*9e564957SAndroid Build Coastguard Worker {
319*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
320*9e564957SAndroid Build Coastguard Worker 	char *newpath;
321*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
322*9e564957SAndroid Build Coastguard Worker 	if (!err) {
323*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_truncate(d->next, newpath, size, fi);
324*9e564957SAndroid Build Coastguard Worker 		free(newpath);
325*9e564957SAndroid Build Coastguard Worker 	}
326*9e564957SAndroid Build Coastguard Worker 	return err;
327*9e564957SAndroid Build Coastguard Worker }
328*9e564957SAndroid Build Coastguard Worker 
subdir_utimens(const char * path,const struct timespec ts[2],struct fuse_file_info * fi)329*9e564957SAndroid Build Coastguard Worker static int subdir_utimens(const char *path, const struct timespec ts[2],
330*9e564957SAndroid Build Coastguard Worker 			  struct fuse_file_info *fi)
331*9e564957SAndroid Build Coastguard Worker {
332*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
333*9e564957SAndroid Build Coastguard Worker 	char *newpath;
334*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
335*9e564957SAndroid Build Coastguard Worker 	if (!err) {
336*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_utimens(d->next, newpath, ts, fi);
337*9e564957SAndroid Build Coastguard Worker 		free(newpath);
338*9e564957SAndroid Build Coastguard Worker 	}
339*9e564957SAndroid Build Coastguard Worker 	return err;
340*9e564957SAndroid Build Coastguard Worker }
341*9e564957SAndroid Build Coastguard Worker 
subdir_create(const char * path,mode_t mode,struct fuse_file_info * fi)342*9e564957SAndroid Build Coastguard Worker static int subdir_create(const char *path, mode_t mode,
343*9e564957SAndroid Build Coastguard Worker 			 struct fuse_file_info *fi)
344*9e564957SAndroid Build Coastguard Worker {
345*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
346*9e564957SAndroid Build Coastguard Worker 	char *newpath;
347*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
348*9e564957SAndroid Build Coastguard Worker 	if (!err) {
349*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_create(d->next, newpath, mode, fi);
350*9e564957SAndroid Build Coastguard Worker 		free(newpath);
351*9e564957SAndroid Build Coastguard Worker 	}
352*9e564957SAndroid Build Coastguard Worker 	return err;
353*9e564957SAndroid Build Coastguard Worker }
354*9e564957SAndroid Build Coastguard Worker 
subdir_open(const char * path,struct fuse_file_info * fi)355*9e564957SAndroid Build Coastguard Worker static int subdir_open(const char *path, struct fuse_file_info *fi)
356*9e564957SAndroid Build Coastguard Worker {
357*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
358*9e564957SAndroid Build Coastguard Worker 	char *newpath;
359*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
360*9e564957SAndroid Build Coastguard Worker 	if (!err) {
361*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_open(d->next, newpath, fi);
362*9e564957SAndroid Build Coastguard Worker 		free(newpath);
363*9e564957SAndroid Build Coastguard Worker 	}
364*9e564957SAndroid Build Coastguard Worker 	return err;
365*9e564957SAndroid Build Coastguard Worker }
366*9e564957SAndroid Build Coastguard Worker 
subdir_read_buf(const char * path,struct fuse_bufvec ** bufp,size_t size,off_t offset,struct fuse_file_info * fi)367*9e564957SAndroid Build Coastguard Worker static int subdir_read_buf(const char *path, struct fuse_bufvec **bufp,
368*9e564957SAndroid Build Coastguard Worker 			   size_t size, off_t offset, struct fuse_file_info *fi)
369*9e564957SAndroid Build Coastguard Worker {
370*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
371*9e564957SAndroid Build Coastguard Worker 	char *newpath;
372*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
373*9e564957SAndroid Build Coastguard Worker 	if (!err) {
374*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_read_buf(d->next, newpath, bufp, size, offset, fi);
375*9e564957SAndroid Build Coastguard Worker 		free(newpath);
376*9e564957SAndroid Build Coastguard Worker 	}
377*9e564957SAndroid Build Coastguard Worker 	return err;
378*9e564957SAndroid Build Coastguard Worker }
379*9e564957SAndroid Build Coastguard Worker 
subdir_write_buf(const char * path,struct fuse_bufvec * buf,off_t offset,struct fuse_file_info * fi)380*9e564957SAndroid Build Coastguard Worker static int subdir_write_buf(const char *path, struct fuse_bufvec *buf,
381*9e564957SAndroid Build Coastguard Worker 			off_t offset, struct fuse_file_info *fi)
382*9e564957SAndroid Build Coastguard Worker {
383*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
384*9e564957SAndroid Build Coastguard Worker 	char *newpath;
385*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
386*9e564957SAndroid Build Coastguard Worker 	if (!err) {
387*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_write_buf(d->next, newpath, buf, offset, fi);
388*9e564957SAndroid Build Coastguard Worker 		free(newpath);
389*9e564957SAndroid Build Coastguard Worker 	}
390*9e564957SAndroid Build Coastguard Worker 	return err;
391*9e564957SAndroid Build Coastguard Worker }
392*9e564957SAndroid Build Coastguard Worker 
subdir_statfs(const char * path,struct statvfs * stbuf)393*9e564957SAndroid Build Coastguard Worker static int subdir_statfs(const char *path, struct statvfs *stbuf)
394*9e564957SAndroid Build Coastguard Worker {
395*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
396*9e564957SAndroid Build Coastguard Worker 	char *newpath;
397*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
398*9e564957SAndroid Build Coastguard Worker 	if (!err) {
399*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_statfs(d->next, newpath, stbuf);
400*9e564957SAndroid Build Coastguard Worker 		free(newpath);
401*9e564957SAndroid Build Coastguard Worker 	}
402*9e564957SAndroid Build Coastguard Worker 	return err;
403*9e564957SAndroid Build Coastguard Worker }
404*9e564957SAndroid Build Coastguard Worker 
subdir_flush(const char * path,struct fuse_file_info * fi)405*9e564957SAndroid Build Coastguard Worker static int subdir_flush(const char *path, struct fuse_file_info *fi)
406*9e564957SAndroid Build Coastguard Worker {
407*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
408*9e564957SAndroid Build Coastguard Worker 	char *newpath;
409*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
410*9e564957SAndroid Build Coastguard Worker 	if (!err) {
411*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_flush(d->next, newpath, fi);
412*9e564957SAndroid Build Coastguard Worker 		free(newpath);
413*9e564957SAndroid Build Coastguard Worker 	}
414*9e564957SAndroid Build Coastguard Worker 	return err;
415*9e564957SAndroid Build Coastguard Worker }
416*9e564957SAndroid Build Coastguard Worker 
subdir_release(const char * path,struct fuse_file_info * fi)417*9e564957SAndroid Build Coastguard Worker static int subdir_release(const char *path, struct fuse_file_info *fi)
418*9e564957SAndroid Build Coastguard Worker {
419*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
420*9e564957SAndroid Build Coastguard Worker 	char *newpath;
421*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
422*9e564957SAndroid Build Coastguard Worker 	if (!err) {
423*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_release(d->next, newpath, fi);
424*9e564957SAndroid Build Coastguard Worker 		free(newpath);
425*9e564957SAndroid Build Coastguard Worker 	}
426*9e564957SAndroid Build Coastguard Worker 	return err;
427*9e564957SAndroid Build Coastguard Worker }
428*9e564957SAndroid Build Coastguard Worker 
subdir_fsync(const char * path,int isdatasync,struct fuse_file_info * fi)429*9e564957SAndroid Build Coastguard Worker static int subdir_fsync(const char *path, int isdatasync,
430*9e564957SAndroid Build Coastguard Worker 			struct fuse_file_info *fi)
431*9e564957SAndroid Build Coastguard Worker {
432*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
433*9e564957SAndroid Build Coastguard Worker 	char *newpath;
434*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
435*9e564957SAndroid Build Coastguard Worker 	if (!err) {
436*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_fsync(d->next, newpath, isdatasync, fi);
437*9e564957SAndroid Build Coastguard Worker 		free(newpath);
438*9e564957SAndroid Build Coastguard Worker 	}
439*9e564957SAndroid Build Coastguard Worker 	return err;
440*9e564957SAndroid Build Coastguard Worker }
441*9e564957SAndroid Build Coastguard Worker 
subdir_fsyncdir(const char * path,int isdatasync,struct fuse_file_info * fi)442*9e564957SAndroid Build Coastguard Worker static int subdir_fsyncdir(const char *path, int isdatasync,
443*9e564957SAndroid Build Coastguard Worker 			   struct fuse_file_info *fi)
444*9e564957SAndroid Build Coastguard Worker {
445*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
446*9e564957SAndroid Build Coastguard Worker 	char *newpath;
447*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
448*9e564957SAndroid Build Coastguard Worker 	if (!err) {
449*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_fsyncdir(d->next, newpath, isdatasync, fi);
450*9e564957SAndroid Build Coastguard Worker 		free(newpath);
451*9e564957SAndroid Build Coastguard Worker 	}
452*9e564957SAndroid Build Coastguard Worker 	return err;
453*9e564957SAndroid Build Coastguard Worker }
454*9e564957SAndroid Build Coastguard Worker 
subdir_setxattr(const char * path,const char * name,const char * value,size_t size,int flags)455*9e564957SAndroid Build Coastguard Worker static int subdir_setxattr(const char *path, const char *name,
456*9e564957SAndroid Build Coastguard Worker 			   const char *value, size_t size, int flags)
457*9e564957SAndroid Build Coastguard Worker {
458*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
459*9e564957SAndroid Build Coastguard Worker 	char *newpath;
460*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
461*9e564957SAndroid Build Coastguard Worker 	if (!err) {
462*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_setxattr(d->next, newpath, name, value, size,
463*9e564957SAndroid Build Coastguard Worker 				       flags);
464*9e564957SAndroid Build Coastguard Worker 		free(newpath);
465*9e564957SAndroid Build Coastguard Worker 	}
466*9e564957SAndroid Build Coastguard Worker 	return err;
467*9e564957SAndroid Build Coastguard Worker }
468*9e564957SAndroid Build Coastguard Worker 
subdir_getxattr(const char * path,const char * name,char * value,size_t size)469*9e564957SAndroid Build Coastguard Worker static int subdir_getxattr(const char *path, const char *name, char *value,
470*9e564957SAndroid Build Coastguard Worker 			   size_t size)
471*9e564957SAndroid Build Coastguard Worker {
472*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
473*9e564957SAndroid Build Coastguard Worker 	char *newpath;
474*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
475*9e564957SAndroid Build Coastguard Worker 	if (!err) {
476*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_getxattr(d->next, newpath, name, value, size);
477*9e564957SAndroid Build Coastguard Worker 		free(newpath);
478*9e564957SAndroid Build Coastguard Worker 	}
479*9e564957SAndroid Build Coastguard Worker 	return err;
480*9e564957SAndroid Build Coastguard Worker }
481*9e564957SAndroid Build Coastguard Worker 
subdir_listxattr(const char * path,char * list,size_t size)482*9e564957SAndroid Build Coastguard Worker static int subdir_listxattr(const char *path, char *list, size_t size)
483*9e564957SAndroid Build Coastguard Worker {
484*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
485*9e564957SAndroid Build Coastguard Worker 	char *newpath;
486*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
487*9e564957SAndroid Build Coastguard Worker 	if (!err) {
488*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_listxattr(d->next, newpath, list, size);
489*9e564957SAndroid Build Coastguard Worker 		free(newpath);
490*9e564957SAndroid Build Coastguard Worker 	}
491*9e564957SAndroid Build Coastguard Worker 	return err;
492*9e564957SAndroid Build Coastguard Worker }
493*9e564957SAndroid Build Coastguard Worker 
subdir_removexattr(const char * path,const char * name)494*9e564957SAndroid Build Coastguard Worker static int subdir_removexattr(const char *path, const char *name)
495*9e564957SAndroid Build Coastguard Worker {
496*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
497*9e564957SAndroid Build Coastguard Worker 	char *newpath;
498*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
499*9e564957SAndroid Build Coastguard Worker 	if (!err) {
500*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_removexattr(d->next, newpath, name);
501*9e564957SAndroid Build Coastguard Worker 		free(newpath);
502*9e564957SAndroid Build Coastguard Worker 	}
503*9e564957SAndroid Build Coastguard Worker 	return err;
504*9e564957SAndroid Build Coastguard Worker }
505*9e564957SAndroid Build Coastguard Worker 
subdir_lock(const char * path,struct fuse_file_info * fi,int cmd,struct flock * lock)506*9e564957SAndroid Build Coastguard Worker static int subdir_lock(const char *path, struct fuse_file_info *fi, int cmd,
507*9e564957SAndroid Build Coastguard Worker 		       struct flock *lock)
508*9e564957SAndroid Build Coastguard Worker {
509*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
510*9e564957SAndroid Build Coastguard Worker 	char *newpath;
511*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
512*9e564957SAndroid Build Coastguard Worker 	if (!err) {
513*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_lock(d->next, newpath, fi, cmd, lock);
514*9e564957SAndroid Build Coastguard Worker 		free(newpath);
515*9e564957SAndroid Build Coastguard Worker 	}
516*9e564957SAndroid Build Coastguard Worker 	return err;
517*9e564957SAndroid Build Coastguard Worker }
518*9e564957SAndroid Build Coastguard Worker 
subdir_flock(const char * path,struct fuse_file_info * fi,int op)519*9e564957SAndroid Build Coastguard Worker static int subdir_flock(const char *path, struct fuse_file_info *fi, int op)
520*9e564957SAndroid Build Coastguard Worker {
521*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
522*9e564957SAndroid Build Coastguard Worker 	char *newpath;
523*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
524*9e564957SAndroid Build Coastguard Worker 	if (!err) {
525*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_flock(d->next, newpath, fi, op);
526*9e564957SAndroid Build Coastguard Worker 		free(newpath);
527*9e564957SAndroid Build Coastguard Worker 	}
528*9e564957SAndroid Build Coastguard Worker 	return err;
529*9e564957SAndroid Build Coastguard Worker }
530*9e564957SAndroid Build Coastguard Worker 
subdir_bmap(const char * path,size_t blocksize,uint64_t * idx)531*9e564957SAndroid Build Coastguard Worker static int subdir_bmap(const char *path, size_t blocksize, uint64_t *idx)
532*9e564957SAndroid Build Coastguard Worker {
533*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
534*9e564957SAndroid Build Coastguard Worker 	char *newpath;
535*9e564957SAndroid Build Coastguard Worker 	int err = subdir_addpath(d, path, &newpath);
536*9e564957SAndroid Build Coastguard Worker 	if (!err) {
537*9e564957SAndroid Build Coastguard Worker 		err = fuse_fs_bmap(d->next, newpath, blocksize, idx);
538*9e564957SAndroid Build Coastguard Worker 		free(newpath);
539*9e564957SAndroid Build Coastguard Worker 	}
540*9e564957SAndroid Build Coastguard Worker 	return err;
541*9e564957SAndroid Build Coastguard Worker }
542*9e564957SAndroid Build Coastguard Worker 
subdir_lseek(const char * path,off_t off,int whence,struct fuse_file_info * fi)543*9e564957SAndroid Build Coastguard Worker static off_t subdir_lseek(const char *path, off_t off, int whence,
544*9e564957SAndroid Build Coastguard Worker 			  struct fuse_file_info *fi)
545*9e564957SAndroid Build Coastguard Worker {
546*9e564957SAndroid Build Coastguard Worker 	struct subdir *ic = subdir_get();
547*9e564957SAndroid Build Coastguard Worker 	char *newpath;
548*9e564957SAndroid Build Coastguard Worker 	int res = subdir_addpath(ic, path, &newpath);
549*9e564957SAndroid Build Coastguard Worker 	if (!res) {
550*9e564957SAndroid Build Coastguard Worker 		res = fuse_fs_lseek(ic->next, newpath, off, whence, fi);
551*9e564957SAndroid Build Coastguard Worker 		free(newpath);
552*9e564957SAndroid Build Coastguard Worker 	}
553*9e564957SAndroid Build Coastguard Worker 	return res;
554*9e564957SAndroid Build Coastguard Worker }
555*9e564957SAndroid Build Coastguard Worker 
subdir_init(struct fuse_conn_info * conn,struct fuse_config * cfg)556*9e564957SAndroid Build Coastguard Worker static void *subdir_init(struct fuse_conn_info *conn,
557*9e564957SAndroid Build Coastguard Worker 			 struct fuse_config *cfg)
558*9e564957SAndroid Build Coastguard Worker {
559*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = subdir_get();
560*9e564957SAndroid Build Coastguard Worker 	fuse_fs_init(d->next, conn, cfg);
561*9e564957SAndroid Build Coastguard Worker 	/* Don't touch cfg->nullpath_ok, we can work with
562*9e564957SAndroid Build Coastguard Worker 	   either */
563*9e564957SAndroid Build Coastguard Worker 	return d;
564*9e564957SAndroid Build Coastguard Worker }
565*9e564957SAndroid Build Coastguard Worker 
subdir_destroy(void * data)566*9e564957SAndroid Build Coastguard Worker static void subdir_destroy(void *data)
567*9e564957SAndroid Build Coastguard Worker {
568*9e564957SAndroid Build Coastguard Worker 	struct subdir *d = data;
569*9e564957SAndroid Build Coastguard Worker 	fuse_fs_destroy(d->next);
570*9e564957SAndroid Build Coastguard Worker 	free(d->base);
571*9e564957SAndroid Build Coastguard Worker 	free(d);
572*9e564957SAndroid Build Coastguard Worker }
573*9e564957SAndroid Build Coastguard Worker 
574*9e564957SAndroid Build Coastguard Worker static const struct fuse_operations subdir_oper = {
575*9e564957SAndroid Build Coastguard Worker 	.destroy	= subdir_destroy,
576*9e564957SAndroid Build Coastguard Worker 	.init		= subdir_init,
577*9e564957SAndroid Build Coastguard Worker 	.getattr	= subdir_getattr,
578*9e564957SAndroid Build Coastguard Worker 	.access		= subdir_access,
579*9e564957SAndroid Build Coastguard Worker 	.readlink	= subdir_readlink,
580*9e564957SAndroid Build Coastguard Worker 	.opendir	= subdir_opendir,
581*9e564957SAndroid Build Coastguard Worker 	.readdir	= subdir_readdir,
582*9e564957SAndroid Build Coastguard Worker 	.releasedir	= subdir_releasedir,
583*9e564957SAndroid Build Coastguard Worker 	.mknod		= subdir_mknod,
584*9e564957SAndroid Build Coastguard Worker 	.mkdir		= subdir_mkdir,
585*9e564957SAndroid Build Coastguard Worker 	.symlink	= subdir_symlink,
586*9e564957SAndroid Build Coastguard Worker 	.unlink		= subdir_unlink,
587*9e564957SAndroid Build Coastguard Worker 	.rmdir		= subdir_rmdir,
588*9e564957SAndroid Build Coastguard Worker 	.rename		= subdir_rename,
589*9e564957SAndroid Build Coastguard Worker 	.link		= subdir_link,
590*9e564957SAndroid Build Coastguard Worker 	.chmod		= subdir_chmod,
591*9e564957SAndroid Build Coastguard Worker 	.chown		= subdir_chown,
592*9e564957SAndroid Build Coastguard Worker 	.truncate	= subdir_truncate,
593*9e564957SAndroid Build Coastguard Worker 	.utimens	= subdir_utimens,
594*9e564957SAndroid Build Coastguard Worker 	.create		= subdir_create,
595*9e564957SAndroid Build Coastguard Worker 	.open		= subdir_open,
596*9e564957SAndroid Build Coastguard Worker 	.read_buf	= subdir_read_buf,
597*9e564957SAndroid Build Coastguard Worker 	.write_buf	= subdir_write_buf,
598*9e564957SAndroid Build Coastguard Worker 	.statfs		= subdir_statfs,
599*9e564957SAndroid Build Coastguard Worker 	.flush		= subdir_flush,
600*9e564957SAndroid Build Coastguard Worker 	.release	= subdir_release,
601*9e564957SAndroid Build Coastguard Worker 	.fsync		= subdir_fsync,
602*9e564957SAndroid Build Coastguard Worker 	.fsyncdir	= subdir_fsyncdir,
603*9e564957SAndroid Build Coastguard Worker 	.setxattr	= subdir_setxattr,
604*9e564957SAndroid Build Coastguard Worker 	.getxattr	= subdir_getxattr,
605*9e564957SAndroid Build Coastguard Worker 	.listxattr	= subdir_listxattr,
606*9e564957SAndroid Build Coastguard Worker 	.removexattr	= subdir_removexattr,
607*9e564957SAndroid Build Coastguard Worker 	.lock		= subdir_lock,
608*9e564957SAndroid Build Coastguard Worker 	.flock		= subdir_flock,
609*9e564957SAndroid Build Coastguard Worker 	.bmap		= subdir_bmap,
610*9e564957SAndroid Build Coastguard Worker 	.lseek		= subdir_lseek,
611*9e564957SAndroid Build Coastguard Worker };
612*9e564957SAndroid Build Coastguard Worker 
613*9e564957SAndroid Build Coastguard Worker static const struct fuse_opt subdir_opts[] = {
614*9e564957SAndroid Build Coastguard Worker 	FUSE_OPT_KEY("-h", 0),
615*9e564957SAndroid Build Coastguard Worker 	FUSE_OPT_KEY("--help", 0),
616*9e564957SAndroid Build Coastguard Worker 	{ "subdir=%s", offsetof(struct subdir, base), 0 },
617*9e564957SAndroid Build Coastguard Worker 	{ "rellinks", offsetof(struct subdir, rellinks), 1 },
618*9e564957SAndroid Build Coastguard Worker 	{ "norellinks", offsetof(struct subdir, rellinks), 0 },
619*9e564957SAndroid Build Coastguard Worker 	FUSE_OPT_END
620*9e564957SAndroid Build Coastguard Worker };
621*9e564957SAndroid Build Coastguard Worker 
subdir_help(void)622*9e564957SAndroid Build Coastguard Worker static void subdir_help(void)
623*9e564957SAndroid Build Coastguard Worker {
624*9e564957SAndroid Build Coastguard Worker 	printf(
625*9e564957SAndroid Build Coastguard Worker "    -o subdir=DIR	    prepend this directory to all paths (mandatory)\n"
626*9e564957SAndroid Build Coastguard Worker "    -o [no]rellinks	    transform absolute symlinks to relative\n");
627*9e564957SAndroid Build Coastguard Worker }
628*9e564957SAndroid Build Coastguard Worker 
subdir_opt_proc(void * data,const char * arg,int key,struct fuse_args * outargs)629*9e564957SAndroid Build Coastguard Worker static int subdir_opt_proc(void *data, const char *arg, int key,
630*9e564957SAndroid Build Coastguard Worker 			   struct fuse_args *outargs)
631*9e564957SAndroid Build Coastguard Worker {
632*9e564957SAndroid Build Coastguard Worker 	(void) data; (void) arg; (void) outargs;
633*9e564957SAndroid Build Coastguard Worker 
634*9e564957SAndroid Build Coastguard Worker 	if (!key) {
635*9e564957SAndroid Build Coastguard Worker 		subdir_help();
636*9e564957SAndroid Build Coastguard Worker 		return -1;
637*9e564957SAndroid Build Coastguard Worker 	}
638*9e564957SAndroid Build Coastguard Worker 
639*9e564957SAndroid Build Coastguard Worker 	return 1;
640*9e564957SAndroid Build Coastguard Worker }
641*9e564957SAndroid Build Coastguard Worker 
subdir_new(struct fuse_args * args,struct fuse_fs * next[])642*9e564957SAndroid Build Coastguard Worker static struct fuse_fs *subdir_new(struct fuse_args *args,
643*9e564957SAndroid Build Coastguard Worker 				  struct fuse_fs *next[])
644*9e564957SAndroid Build Coastguard Worker {
645*9e564957SAndroid Build Coastguard Worker 	struct fuse_fs *fs;
646*9e564957SAndroid Build Coastguard Worker 	struct subdir *d;
647*9e564957SAndroid Build Coastguard Worker 
648*9e564957SAndroid Build Coastguard Worker 	d = calloc(1, sizeof(struct subdir));
649*9e564957SAndroid Build Coastguard Worker 	if (d == NULL) {
650*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR, "fuse-subdir: memory allocation failed\n");
651*9e564957SAndroid Build Coastguard Worker 		return NULL;
652*9e564957SAndroid Build Coastguard Worker 	}
653*9e564957SAndroid Build Coastguard Worker 
654*9e564957SAndroid Build Coastguard Worker 	if (fuse_opt_parse(args, d, subdir_opts, subdir_opt_proc) == -1)
655*9e564957SAndroid Build Coastguard Worker 		goto out_free;
656*9e564957SAndroid Build Coastguard Worker 
657*9e564957SAndroid Build Coastguard Worker 	if (!next[0] || next[1]) {
658*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR, "fuse-subdir: exactly one next filesystem required\n");
659*9e564957SAndroid Build Coastguard Worker 		goto out_free;
660*9e564957SAndroid Build Coastguard Worker 	}
661*9e564957SAndroid Build Coastguard Worker 
662*9e564957SAndroid Build Coastguard Worker 	if (!d->base) {
663*9e564957SAndroid Build Coastguard Worker 		fuse_log(FUSE_LOG_ERR, "fuse-subdir: missing 'subdir' option\n");
664*9e564957SAndroid Build Coastguard Worker 		goto out_free;
665*9e564957SAndroid Build Coastguard Worker 	}
666*9e564957SAndroid Build Coastguard Worker 
667*9e564957SAndroid Build Coastguard Worker 	if (d->base[0] && d->base[strlen(d->base)-1] != '/') {
668*9e564957SAndroid Build Coastguard Worker 		char *tmp = realloc(d->base, strlen(d->base) + 2);
669*9e564957SAndroid Build Coastguard Worker 		if (!tmp) {
670*9e564957SAndroid Build Coastguard Worker 			fuse_log(FUSE_LOG_ERR, "fuse-subdir: memory allocation failed\n");
671*9e564957SAndroid Build Coastguard Worker 			goto out_free;
672*9e564957SAndroid Build Coastguard Worker 		}
673*9e564957SAndroid Build Coastguard Worker 		d->base = tmp;
674*9e564957SAndroid Build Coastguard Worker 		strcat(d->base, "/");
675*9e564957SAndroid Build Coastguard Worker 	}
676*9e564957SAndroid Build Coastguard Worker 	d->baselen = strlen(d->base);
677*9e564957SAndroid Build Coastguard Worker 	d->next = next[0];
678*9e564957SAndroid Build Coastguard Worker 	fs = fuse_fs_new(&subdir_oper, sizeof(subdir_oper), d);
679*9e564957SAndroid Build Coastguard Worker 	if (!fs)
680*9e564957SAndroid Build Coastguard Worker 		goto out_free;
681*9e564957SAndroid Build Coastguard Worker 	return fs;
682*9e564957SAndroid Build Coastguard Worker 
683*9e564957SAndroid Build Coastguard Worker out_free:
684*9e564957SAndroid Build Coastguard Worker 	free(d->base);
685*9e564957SAndroid Build Coastguard Worker 	free(d);
686*9e564957SAndroid Build Coastguard Worker 	return NULL;
687*9e564957SAndroid Build Coastguard Worker }
688*9e564957SAndroid Build Coastguard Worker 
689*9e564957SAndroid Build Coastguard Worker FUSE_REGISTER_MODULE(subdir, subdir_new);
690