xref: /netbsd-src/share/examples/refuse/fanoutfs/fanoutfs.c (revision b143e0b001b5dc4c4ab2a3ac3b69169be612eb66)
1f44794b2Sagc /*
2f44794b2Sagc  * Copyright � 2007 Alistair Crooks.  All rights reserved.
3f44794b2Sagc  *
4f44794b2Sagc  * Redistribution and use in source and binary forms, with or without
5f44794b2Sagc  * modification, are permitted provided that the following conditions
6f44794b2Sagc  * are met:
7f44794b2Sagc  * 1. Redistributions of source code must retain the above copyright
8f44794b2Sagc  *    notice, this list of conditions and the following disclaimer.
9f44794b2Sagc  * 2. Redistributions in binary form must reproduce the above copyright
10f44794b2Sagc  *    notice, this list of conditions and the following disclaimer in the
11f44794b2Sagc  *    documentation and/or other materials provided with the distribution.
12f44794b2Sagc  * 3. The name of the author may not be used to endorse or promote
13f44794b2Sagc  *    products derived from this software without specific prior written
14f44794b2Sagc  *    permission.
15f44794b2Sagc  *
16f44794b2Sagc  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17f44794b2Sagc  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18f44794b2Sagc  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f44794b2Sagc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20f44794b2Sagc  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f44794b2Sagc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22f44794b2Sagc  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23f44794b2Sagc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24f44794b2Sagc  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25f44794b2Sagc  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26f44794b2Sagc  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27f44794b2Sagc  */
28f44794b2Sagc #include <sys/types.h>
29f44794b2Sagc #include <sys/stat.h>
30f44794b2Sagc 
31f44794b2Sagc #include <ctype.h>
32f44794b2Sagc #include <dirent.h>
33f44794b2Sagc #include <err.h>
34f44794b2Sagc #include <errno.h>
35f44794b2Sagc #include <fcntl.h>
36f44794b2Sagc #include <fuse.h>
37f44794b2Sagc #include <signal.h>
38f44794b2Sagc #include <stdio.h>
39f44794b2Sagc #include <stdlib.h>
40f44794b2Sagc #include <string.h>
41f44794b2Sagc #include <time.h>
42f44794b2Sagc #include <unistd.h>
43f44794b2Sagc 
44f44794b2Sagc #include "defs.h"
45f44794b2Sagc 
46f44794b2Sagc #ifndef PREFIX
47f44794b2Sagc #define PREFIX		""
48f44794b2Sagc #endif
49f44794b2Sagc 
50f44794b2Sagc #ifndef DEF_CONF_FILE
51f44794b2Sagc #define DEF_CONF_FILE	"/etc/fanoutfs.conf"
52f44794b2Sagc #endif
53f44794b2Sagc 
54f44794b2Sagc DEFINE_ARRAY(strv_t, char *);
55f44794b2Sagc 
56f44794b2Sagc static struct stat	 vfs;		/* stat info of directory */
57f44794b2Sagc static strv_t		 dirs;		/* the directories, in order */
58f44794b2Sagc static char		*conffile;	/* configuration file name */
59f44794b2Sagc static int		 verbose; 	/* how chatty are we? */
60f44794b2Sagc 
61f44794b2Sagc 
62f44794b2Sagc 
63f44794b2Sagc 
64f44794b2Sagc 
65f44794b2Sagc /********************************************************************/
66f44794b2Sagc 
67f44794b2Sagc static int
readconf(const char * f)68f44794b2Sagc readconf(const char *f)
69f44794b2Sagc {
70f44794b2Sagc 	char	 buf[BUFSIZ];
71f44794b2Sagc 	char	*cp;
72f44794b2Sagc 	FILE	*fp;
73f44794b2Sagc 	int	 line;
74f44794b2Sagc 
75f44794b2Sagc 	if ((fp = fopen((f) ? f : PREFIX DEF_CONF_FILE, "r")) == NULL) {
76f44794b2Sagc 		warn("can't read configuration file `%s'\n", f);
77f44794b2Sagc 		return 0;
78f44794b2Sagc 	}
79f44794b2Sagc 	for (line = 1 ;  fgets(buf, sizeof(buf), fp) != NULL ; line += 1) {
80f44794b2Sagc 		buf[strlen(buf) - 1] = 0x0;
81f44794b2Sagc 		for (cp = buf ; *cp && isspace((unsigned)*cp) ; cp++) {
82f44794b2Sagc 		}
83f44794b2Sagc 		if (*cp == '\n' || *cp == 0x0 || *cp == '#') {
84f44794b2Sagc 			continue;
85f44794b2Sagc 		}
86f44794b2Sagc 		ALLOC(char *, dirs.v, dirs.size, dirs.c, 10, 10,
87f44794b2Sagc 			"readconf", exit(EXIT_FAILURE));
88f44794b2Sagc 		dirs.v[dirs.c++] = strdup(cp);
89f44794b2Sagc 	}
90f44794b2Sagc 	(void) fclose(fp);
91f44794b2Sagc 	return 1;
92f44794b2Sagc }
93f44794b2Sagc 
94f44794b2Sagc /* yes, this does too much work */
95f44794b2Sagc static void
sighup(int n)96f44794b2Sagc sighup(int n)
97f44794b2Sagc {
98f44794b2Sagc 	int	i;
99f44794b2Sagc 
100f44794b2Sagc 	printf("Reading configuration file `%s'\n", conffile);
101f44794b2Sagc 	for (i = 0 ; i < dirs.c ; i++) {
102f44794b2Sagc 		FREE(dirs.v[i]);
103f44794b2Sagc 	}
104f44794b2Sagc 	dirs.c = 0;
105f44794b2Sagc 	readconf(conffile);
106f44794b2Sagc }
107f44794b2Sagc 
108f44794b2Sagc /* find the correct entry in the list of directories */
109f44794b2Sagc static int
findentry(const char * path,char * name,size_t namesize,struct stat * sp)110f44794b2Sagc findentry(const char *path, char *name, size_t namesize, struct stat *sp)
111f44794b2Sagc {
112f44794b2Sagc 	struct stat	st;
113f44794b2Sagc 	int		i;
114f44794b2Sagc 
115f44794b2Sagc 	if (sp == NULL) {
116f44794b2Sagc 		sp = &st;
117f44794b2Sagc 	}
118f44794b2Sagc 	for (i = 0 ; i < dirs.c ; i++) {
119f44794b2Sagc 		(void) snprintf(name, namesize, "%s%s", dirs.v[i], path);
120f44794b2Sagc 		if (stat(name, sp) == 0) {
121*b143e0b0Sagc 			return i;
122f44794b2Sagc 		}
123f44794b2Sagc 	}
124*b143e0b0Sagc 	return -1;
125f44794b2Sagc }
126f44794b2Sagc 
127f44794b2Sagc /* return 1 if the string `s' is present in the array */
128f44794b2Sagc static int
present(char * s,strv_t * sp)129f44794b2Sagc present(char *s, strv_t *sp)
130f44794b2Sagc {
131f44794b2Sagc 	int	i;
132f44794b2Sagc 
133f44794b2Sagc 	for (i = 0 ; i < sp->c && strcmp(s, sp->v[i]) != 0 ; i++) {
134f44794b2Sagc 	}
135f44794b2Sagc 	return (i < sp->c);
136f44794b2Sagc }
137f44794b2Sagc 
138f44794b2Sagc /* make sure the directory hierarchy exists */
139f44794b2Sagc static int
mkdirs(char * path)140f44794b2Sagc mkdirs(char *path)
141f44794b2Sagc {
142f44794b2Sagc 	char	 name[MAXPATHLEN];
143f44794b2Sagc 	char	*slash;
144f44794b2Sagc 
145f44794b2Sagc 	(void) snprintf(name, sizeof(name), "%s%s", dirs.v[0], path);
146f44794b2Sagc 	slash = &name[strlen(path) + 1];
147f44794b2Sagc 	while ((slash = strchr(slash, '/')) != NULL) {
148f44794b2Sagc 		*slash = 0x0;
149f44794b2Sagc printf("mkdirs: dir `%s'\n", name);
150f44794b2Sagc 		if (mkdir(name, 0777) < 0) {
151f44794b2Sagc 			return 0;
152f44794b2Sagc 		}
153f44794b2Sagc 		*slash = '/';
154f44794b2Sagc 	}
155f44794b2Sagc 	return 1;
156f44794b2Sagc }
157f44794b2Sagc 
158*b143e0b0Sagc /* copy a file, preserving mode, to make it writable */
159*b143e0b0Sagc static int
copyfile(char * from,char * to)160*b143e0b0Sagc copyfile(char *from, char *to)
161*b143e0b0Sagc {
162*b143e0b0Sagc 	struct stat	st;
163*b143e0b0Sagc 	char		buf[BUFSIZ * 10];
164*b143e0b0Sagc 	int		fdfrom;
165*b143e0b0Sagc 	int		fdto;
166*b143e0b0Sagc 	int		ret;
167*b143e0b0Sagc 	int		cc;
168*b143e0b0Sagc 
169*b143e0b0Sagc 	if ((fdfrom = open(from, O_RDONLY, 0666)) < 0) {
170*b143e0b0Sagc 		warn("can't open file `%s' for reading", from);
171*b143e0b0Sagc 		return 0;
172*b143e0b0Sagc 	}
173*b143e0b0Sagc 	(void) fstat(fdfrom, &st);
174*b143e0b0Sagc 	if ((fdto = open(to, O_WRONLY | O_CREAT | O_EXCL, st.st_mode & 07777)) < 0) {
175*b143e0b0Sagc 		warn("can't open file `%s' for reading", from);
176*b143e0b0Sagc 		close(fdfrom);
177*b143e0b0Sagc 		return 0;
178*b143e0b0Sagc 	}
179*b143e0b0Sagc 	for (ret = 1 ; ret && (cc = read(fdfrom, buf, sizeof(buf))) > 0 ; ) {
180*b143e0b0Sagc 		if (write(fdto, buf, cc) != cc) {
181*b143e0b0Sagc 			warn("short write");
182*b143e0b0Sagc 			ret = 0;
183*b143e0b0Sagc 		}
184*b143e0b0Sagc 	}
185*b143e0b0Sagc 	if (fchown(fdto, st.st_uid, st.st_gid) < 0) {
186*b143e0b0Sagc 		warn("bad fchown");
187*b143e0b0Sagc 		ret = 0;
188*b143e0b0Sagc 	}
189*b143e0b0Sagc 	(void) close(fdfrom);
190*b143e0b0Sagc 	(void) close(fdto);
191*b143e0b0Sagc 	return ret;
192*b143e0b0Sagc }
193*b143e0b0Sagc 
194f44794b2Sagc /* file system operations start here */
195f44794b2Sagc 
196f44794b2Sagc /* perform the stat operation */
197f44794b2Sagc static int
fanoutfs_getattr(const char * path,struct stat * st)198f44794b2Sagc fanoutfs_getattr(const char *path, struct stat *st)
199f44794b2Sagc {
200f44794b2Sagc 	char	name[MAXPATHLEN];
201f44794b2Sagc 
202f44794b2Sagc 	(void) memset(st, 0x0, sizeof(*st));
203f44794b2Sagc 	if (strcmp(path, "/") == 0) {
204f44794b2Sagc 		st->st_mode = S_IFDIR | 0755;
205f44794b2Sagc 		st->st_nlink = 2;
206f44794b2Sagc 		return 0;
207f44794b2Sagc 	}
208*b143e0b0Sagc 	if (findentry(path, name, sizeof(name), st) < 0) {
209f44794b2Sagc 		return -ENOENT;
210f44794b2Sagc 	}
211f44794b2Sagc 	return 0;
212f44794b2Sagc }
213f44794b2Sagc 
214f44794b2Sagc /* readdir operation */
215f44794b2Sagc static int
fanoutfs_readdir(const char * path,void * buf,fuse_fill_dir_t filler,off_t offset,struct fuse_file_info * fi)216f44794b2Sagc fanoutfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
217f44794b2Sagc 	      off_t offset, struct fuse_file_info *fi)
218f44794b2Sagc {
219f44794b2Sagc 	struct dirent	*dp;
220f44794b2Sagc 	strv_t		 names;
221f44794b2Sagc 	char		 name[MAXPATHLEN];
222f44794b2Sagc 	DIR		*dirp;
223f44794b2Sagc 	int		 i;
224f44794b2Sagc 
225f44794b2Sagc 	(void) fi;
226f44794b2Sagc 
227f44794b2Sagc 	(void) memset(&names, 0x0, sizeof(names));
228f44794b2Sagc 	for (i = 0 ; i < dirs.c ; i++) {
229f44794b2Sagc 		(void) snprintf(name, sizeof(name), "%s%s", dirs.v[i], path);
230f44794b2Sagc 		if ((dirp = opendir(name)) == NULL) {
231f44794b2Sagc 			continue;
232f44794b2Sagc 		}
233f44794b2Sagc 		while ((dp = readdir(dirp)) != NULL) {
234f44794b2Sagc 			if (!present(dp->d_name, &names)) {
235f44794b2Sagc 				ALLOC(char *, names.v, names.size, names.c,
236f44794b2Sagc 					10, 10, "readdir", exit(EXIT_FAILURE));
237f44794b2Sagc 				names.v[names.c++] = strdup(dp->d_name);
238f44794b2Sagc 			}
239f44794b2Sagc 		}
240f44794b2Sagc 		(void) closedir(dirp);
241f44794b2Sagc 	}
242f44794b2Sagc 	for (i = 0 ; i < names.c ; i++) {
243f44794b2Sagc 		(void) filler(buf, names.v[i], NULL, 0);
244f44794b2Sagc 		FREE(names.v[i]);
245f44794b2Sagc 	}
246f44794b2Sagc 	if (i > 0) {
247f44794b2Sagc 		FREE(names.v);
248f44794b2Sagc 	}
249f44794b2Sagc 	return 0;
250f44794b2Sagc }
251f44794b2Sagc 
252f44794b2Sagc /* open the file in the file system */
253f44794b2Sagc static int
fanoutfs_open(const char * path,struct fuse_file_info * fi)254f44794b2Sagc fanoutfs_open(const char *path, struct fuse_file_info *fi)
255f44794b2Sagc {
256*b143e0b0Sagc 	char	newname[MAXPATHLEN];
257f44794b2Sagc 	char	name[MAXPATHLEN];
258*b143e0b0Sagc 	int	d;
259f44794b2Sagc 
260*b143e0b0Sagc 	if ((d = findentry(path, name, sizeof(name), NULL)) < 0) {
261f44794b2Sagc 		return -ENOENT;
262f44794b2Sagc 	}
263*b143e0b0Sagc 	if (d > 0 && (fi->flags & 0x3) != O_RDONLY) {
264*b143e0b0Sagc 		/* need to copy file to writable dir */
265*b143e0b0Sagc 		(void) snprintf(newname, sizeof(newname), "%s%s", dirs.v[0], path);
266*b143e0b0Sagc 		if (!mkdirs(newname)) {
267*b143e0b0Sagc 			return -ENOENT;
268*b143e0b0Sagc 		}
269*b143e0b0Sagc 		if (!copyfile(name, newname)) {
270*b143e0b0Sagc 			return -EPERM;
271*b143e0b0Sagc 		}
272*b143e0b0Sagc 	}
273f44794b2Sagc 	return 0;
274f44794b2Sagc }
275f44794b2Sagc 
276f44794b2Sagc /* read the file's contents in the file system */
277f44794b2Sagc static int
fanoutfs_read(const char * path,char * buf,size_t size,off_t offset,struct fuse_file_info * fi)278f44794b2Sagc fanoutfs_read(const char *path, char *buf, size_t size, off_t offset,
279f44794b2Sagc 	   struct fuse_file_info * fi)
280f44794b2Sagc {
281f44794b2Sagc 	char	name[MAXPATHLEN];
282f44794b2Sagc 	int	fd;
283f44794b2Sagc 	int	cc;
284f44794b2Sagc 
285f44794b2Sagc 	(void) fi;
286f44794b2Sagc 
287*b143e0b0Sagc 	if (findentry(path, name, sizeof(name), NULL) < 0) {
288f44794b2Sagc 		return -ENOENT;
289f44794b2Sagc 	}
290f44794b2Sagc 	if ((fd = open(name, O_RDONLY, 0666)) < 0) {
291f44794b2Sagc 		return -ENOENT;
292f44794b2Sagc 	}
293f44794b2Sagc 	if (lseek(fd, offset, SEEK_SET) < 0) {
294f44794b2Sagc 		(void) close(fd);
295f44794b2Sagc 		return -EBADF;
296f44794b2Sagc 	}
297f44794b2Sagc 	if ((cc = read(fd, buf, size)) < 0) {
298f44794b2Sagc 		(void) close(fd);
299f44794b2Sagc 		return -errno;
300f44794b2Sagc 	}
301f44794b2Sagc 	(void) close(fd);
302f44794b2Sagc 	return cc;
303f44794b2Sagc }
304f44794b2Sagc 
305f44794b2Sagc /* write the file's contents in the file system */
306f44794b2Sagc static int
fanoutfs_write(const char * path,const char * buf,size_t size,off_t offset,struct fuse_file_info * fi)307f44794b2Sagc fanoutfs_write(const char *path, const char *buf, size_t size, off_t offset,
308f44794b2Sagc 	   struct fuse_file_info * fi)
309f44794b2Sagc {
310f44794b2Sagc 	char	name[MAXPATHLEN];
311f44794b2Sagc 	int	fd;
312f44794b2Sagc 	int	cc;
313f44794b2Sagc 
314f44794b2Sagc 	(void) fi;
315f44794b2Sagc 
316*b143e0b0Sagc 	if (findentry(path, name, sizeof(name), NULL) < 0) {
317f44794b2Sagc 		return -ENOENT;
318f44794b2Sagc 	}
319f44794b2Sagc 	if ((fd = open(name, O_WRONLY, 0666)) < 0) {
320f44794b2Sagc 		return -ENOENT;
321f44794b2Sagc 	}
322f44794b2Sagc 	if (lseek(fd, offset, SEEK_SET) < 0) {
323f44794b2Sagc 		(void) close(fd);
324f44794b2Sagc 		return -EBADF;
325f44794b2Sagc 	}
326f44794b2Sagc 	if ((cc = write(fd, buf, size)) < 0) {
327f44794b2Sagc 		(void) close(fd);
328f44794b2Sagc 		return -errno;
329f44794b2Sagc 	}
330f44794b2Sagc 	(void) close(fd);
331f44794b2Sagc 	return cc;
332f44794b2Sagc }
333f44794b2Sagc 
334f44794b2Sagc /* fill in the statvfs struct */
335f44794b2Sagc static int
fanoutfs_statfs(const char * path,struct statvfs * st)336f44794b2Sagc fanoutfs_statfs(const char *path, struct statvfs *st)
337f44794b2Sagc {
338f44794b2Sagc 	(void) memset(st, 0x0, sizeof(*st));
339f44794b2Sagc 	st->f_bsize = st->f_frsize = st->f_iosize = 512;
340f44794b2Sagc 	st->f_owner = vfs.st_uid;
341f44794b2Sagc 	st->f_files = 1;
342f44794b2Sagc 	return 0;
343f44794b2Sagc }
344f44794b2Sagc 
345f44794b2Sagc /* "remove" a file */
346f44794b2Sagc static int
fanoutfs_unlink(const char * path)347f44794b2Sagc fanoutfs_unlink(const char *path)
348f44794b2Sagc {
349f44794b2Sagc 	char	name[MAXPATHLEN];
350f44794b2Sagc 
351*b143e0b0Sagc 	if (findentry(path, name, sizeof(name), NULL) < 0) {
352f44794b2Sagc 		return -ENOENT;
353f44794b2Sagc 	}
354f44794b2Sagc 	if (unlink(name) < 0) {
355f44794b2Sagc 		return -errno;
356f44794b2Sagc 	}
357f44794b2Sagc 	return 0;
358f44794b2Sagc }
359f44794b2Sagc 
360f44794b2Sagc /* check the access on a file */
361f44794b2Sagc static int
fanoutfs_access(const char * path,int acc)362f44794b2Sagc fanoutfs_access(const char *path, int acc)
363f44794b2Sagc {
364f44794b2Sagc 	char	name[MAXPATHLEN];
365f44794b2Sagc 
366*b143e0b0Sagc 	if (findentry(path, name, sizeof(name), NULL) < 0) {
367f44794b2Sagc 		return -ENOENT;
368f44794b2Sagc 	}
369f44794b2Sagc 	if (access(name, acc) < 0) {
370f44794b2Sagc 		return -errno;
371f44794b2Sagc 	}
372f44794b2Sagc 	return 0;
373f44794b2Sagc }
374f44794b2Sagc 
375f44794b2Sagc /* change the mode of a file */
376f44794b2Sagc static int
fanoutfs_chmod(const char * path,mode_t mode)377f44794b2Sagc fanoutfs_chmod(const char *path, mode_t mode)
378f44794b2Sagc {
379f44794b2Sagc 	char	name[MAXPATHLEN];
380f44794b2Sagc 
381*b143e0b0Sagc 	if (findentry(path, name, sizeof(name), NULL) < 0) {
382f44794b2Sagc 		return -ENOENT;
383f44794b2Sagc 	}
384f44794b2Sagc 	if (chmod(name, mode) < 0) {
385f44794b2Sagc 		return -errno;
386f44794b2Sagc 	}
387f44794b2Sagc 	return 0;
388f44794b2Sagc }
389f44794b2Sagc 
390f44794b2Sagc /* change the owner and group of a file */
391f44794b2Sagc static int
fanoutfs_chown(const char * path,uid_t uid,gid_t gid)392f44794b2Sagc fanoutfs_chown(const char *path, uid_t uid, gid_t gid)
393f44794b2Sagc {
394f44794b2Sagc 	char	name[MAXPATHLEN];
395f44794b2Sagc 
396*b143e0b0Sagc 	if (findentry(path, name, sizeof(name), NULL) < 0) {
397f44794b2Sagc 		return -ENOENT;
398f44794b2Sagc 	}
399f44794b2Sagc 	if (lchown(name, uid, gid) < 0) {
400f44794b2Sagc 		return -errno;
401f44794b2Sagc 	}
402f44794b2Sagc 	return 0;
403f44794b2Sagc }
404f44794b2Sagc 
405f44794b2Sagc /* "rename" a file */
406f44794b2Sagc static int
fanoutfs_rename(const char * from,const char * to)407f44794b2Sagc fanoutfs_rename(const char *from, const char *to)
408f44794b2Sagc {
409f44794b2Sagc 	char	fromname[MAXPATHLEN];
410f44794b2Sagc 	char	toname[MAXPATHLEN];
411f44794b2Sagc 
412*b143e0b0Sagc 	if (findentry(from, fromname, sizeof(fromname), NULL) < 0) {
413f44794b2Sagc 		return -ENOENT;
414f44794b2Sagc 	}
415f44794b2Sagc 	(void) snprintf(toname, sizeof(toname), "%s%s", dirs.v[0], to);
416f44794b2Sagc 	if (!mkdirs(toname)) {
417f44794b2Sagc 		return -ENOENT;
418f44794b2Sagc 	}
419f44794b2Sagc 	if (rename(fromname, toname) < 0) {
420f44794b2Sagc 		return -EPERM;
421f44794b2Sagc 	}
422f44794b2Sagc 	return 0;
423f44794b2Sagc }
424f44794b2Sagc 
425f44794b2Sagc /* create a file */
426f44794b2Sagc static int
fanoutfs_create(const char * path,mode_t mode,struct fuse_file_info * fi)427f44794b2Sagc fanoutfs_create(const char *path, mode_t mode, struct fuse_file_info *fi)
428f44794b2Sagc {
429f44794b2Sagc 	struct stat	st;
430f44794b2Sagc 	char		name[MAXPATHLEN];
431f44794b2Sagc 	int		fd;
432f44794b2Sagc 
433*b143e0b0Sagc 	if (findentry(path, name, sizeof(name), &st) >= 0) {
434f44794b2Sagc 		return -EEXIST;
435f44794b2Sagc 	}
436f44794b2Sagc 	if ((fd = open(name, O_RDWR | O_CREAT | O_EXCL, 0666)) < 0) {
437f44794b2Sagc 		return -EPERM;
438f44794b2Sagc 	}
439f44794b2Sagc 	(void) close(fd);
440f44794b2Sagc 	return 0;
441f44794b2Sagc }
442f44794b2Sagc 
443f44794b2Sagc /* create a special node */
444f44794b2Sagc static int
fanoutfs_mknod(const char * path,mode_t mode,dev_t d)445f44794b2Sagc fanoutfs_mknod(const char *path, mode_t mode, dev_t d)
446f44794b2Sagc {
447f44794b2Sagc 	struct stat	st;
448f44794b2Sagc 	char		name[MAXPATHLEN];
449f44794b2Sagc 
450*b143e0b0Sagc 	if (findentry(path, name, sizeof(name), &st) >= 0) {
451f44794b2Sagc 		return -EEXIST;
452f44794b2Sagc 	}
453f44794b2Sagc 	if (mknod(name, mode, d) < 0) {
454f44794b2Sagc 		return -EPERM;
455f44794b2Sagc 	}
456f44794b2Sagc 	return 0;
457f44794b2Sagc }
458f44794b2Sagc 
459f44794b2Sagc /* create a directory */
460f44794b2Sagc static int
fanoutfs_mkdir(const char * path,mode_t mode)461f44794b2Sagc fanoutfs_mkdir(const char *path, mode_t mode)
462f44794b2Sagc {
463f44794b2Sagc 	char	name[MAXPATHLEN];
464f44794b2Sagc 
465f44794b2Sagc 	(void) snprintf(name, sizeof(name), "%s%s", dirs.v[0], path);
466f44794b2Sagc 	if (!mkdirs(name)) {
467f44794b2Sagc 		return -ENOENT;
468f44794b2Sagc 	}
469f44794b2Sagc 	if (mkdir(name, mode) < 0) {
470f44794b2Sagc 		return -EPERM;
471f44794b2Sagc 	}
472f44794b2Sagc 	return 0;
473f44794b2Sagc }
474f44794b2Sagc 
475f44794b2Sagc /* create a symbolic link */
476f44794b2Sagc static int
fanoutfs_symlink(const char * path,const char * tgt)477f44794b2Sagc fanoutfs_symlink(const char *path, const char *tgt)
478f44794b2Sagc {
479f44794b2Sagc 	char	name[MAXPATHLEN];
480f44794b2Sagc 
481f44794b2Sagc 	(void) snprintf(name, sizeof(name), "%s%s", dirs.v[0], path);
482f44794b2Sagc 	if (!mkdirs(name)) {
483f44794b2Sagc 		return -ENOENT;
484f44794b2Sagc 	}
485f44794b2Sagc 	if (symlink(name, tgt) < 0) {
486f44794b2Sagc 		return -EPERM;
487f44794b2Sagc 	}
488f44794b2Sagc 	return 0;
489f44794b2Sagc }
490f44794b2Sagc 
491f44794b2Sagc /* create a link */
492f44794b2Sagc static int
fanoutfs_link(const char * path,const char * tgt)493f44794b2Sagc fanoutfs_link(const char *path, const char *tgt)
494f44794b2Sagc {
495f44794b2Sagc 	char	name[MAXPATHLEN];
496f44794b2Sagc 
497f44794b2Sagc 	(void) snprintf(name, sizeof(name), "%s%s", dirs.v[0], path);
498f44794b2Sagc 	if (!mkdirs(name)) {
499f44794b2Sagc 		return -ENOENT;
500f44794b2Sagc 	}
501f44794b2Sagc 	if (link(name, tgt) < 0) {
502f44794b2Sagc 		return -errno;
503f44794b2Sagc 	}
504f44794b2Sagc 	return 0;
505f44794b2Sagc }
506f44794b2Sagc 
507f44794b2Sagc /* read the contents of a symbolic link */
508f44794b2Sagc static int
fanoutfs_readlink(const char * path,char * buf,size_t size)509f44794b2Sagc fanoutfs_readlink(const char *path, char *buf, size_t size)
510f44794b2Sagc {
511f44794b2Sagc 	char	name[MAXPATHLEN];
512f44794b2Sagc 
513*b143e0b0Sagc 	if (findentry(path, name, sizeof(name), NULL) < 0) {
514f44794b2Sagc 		return -ENOENT;
515f44794b2Sagc 	}
516f44794b2Sagc 	if (readlink(name, buf, size) < 0) {
517f44794b2Sagc 		return -errno;
518f44794b2Sagc 	}
519f44794b2Sagc 	return 0;
520f44794b2Sagc }
521f44794b2Sagc 
522f44794b2Sagc /* remove a directory */
523f44794b2Sagc static int
fanoutfs_rmdir(const char * path)524f44794b2Sagc fanoutfs_rmdir(const char *path)
525f44794b2Sagc {
526f44794b2Sagc 	char	name[MAXPATHLEN];
527f44794b2Sagc 
528*b143e0b0Sagc 	if (findentry(path, name, sizeof(name), NULL) < 0) {
529f44794b2Sagc 		return -ENOENT;
530f44794b2Sagc 	}
531f44794b2Sagc 	if (rmdir(name) < 0) {
532f44794b2Sagc 		return -errno;
533f44794b2Sagc 	}
534f44794b2Sagc 	return 0;
535f44794b2Sagc }
536f44794b2Sagc 
537f44794b2Sagc /* truncate a file */
538f44794b2Sagc static int
fanoutfs_truncate(const char * path,off_t size)539f44794b2Sagc fanoutfs_truncate(const char *path, off_t size)
540f44794b2Sagc {
541f44794b2Sagc 	char	name[MAXPATHLEN];
542f44794b2Sagc 
543*b143e0b0Sagc 	if (findentry(path, name, sizeof(name), NULL) < 0) {
544f44794b2Sagc 		return -ENOENT;
545f44794b2Sagc 	}
546f44794b2Sagc 	if (truncate(name, size) < 0) {
547f44794b2Sagc 		return -errno;
548f44794b2Sagc 	}
549f44794b2Sagc 	return 0;
550f44794b2Sagc }
551f44794b2Sagc 
552f44794b2Sagc /* set utimes on a file */
553f44794b2Sagc static int
fanoutfs_utime(const char * path,struct utimbuf * t)554f44794b2Sagc fanoutfs_utime(const char *path, struct utimbuf *t)
555f44794b2Sagc {
556f44794b2Sagc 	char	name[MAXPATHLEN];
557f44794b2Sagc 
558*b143e0b0Sagc 	if (findentry(path, name, sizeof(name), NULL) < 0) {
559f44794b2Sagc 		return -ENOENT;
560f44794b2Sagc 	}
561f44794b2Sagc 	if (utime(name, t) < 0) {
562f44794b2Sagc 		return -errno;
563f44794b2Sagc 	}
564f44794b2Sagc 	return 0;
565f44794b2Sagc }
566f44794b2Sagc 
567f44794b2Sagc /* operations struct */
568f44794b2Sagc static struct fuse_operations fanoutfs_oper = {
569f44794b2Sagc 	.getattr = fanoutfs_getattr,
570f44794b2Sagc 	.readlink = fanoutfs_readlink,
571f44794b2Sagc 	.mknod = fanoutfs_mknod,
572f44794b2Sagc 	.mkdir = fanoutfs_mkdir,
573f44794b2Sagc 	.unlink = fanoutfs_unlink,
574f44794b2Sagc 	.rmdir = fanoutfs_rmdir,
575f44794b2Sagc 	.symlink = fanoutfs_symlink,
576f44794b2Sagc 	.rename = fanoutfs_rename,
577f44794b2Sagc 	.link = fanoutfs_link,
578f44794b2Sagc 	.chmod = fanoutfs_chmod,
579f44794b2Sagc 	.chown = fanoutfs_chown,
580f44794b2Sagc 	.truncate = fanoutfs_truncate,
581f44794b2Sagc 	.utime = fanoutfs_utime,
582f44794b2Sagc 	.open = fanoutfs_open,
583f44794b2Sagc 	.read = fanoutfs_read,
584f44794b2Sagc 	.write = fanoutfs_write,
585f44794b2Sagc 	.statfs = fanoutfs_statfs,
586f44794b2Sagc 	.readdir = fanoutfs_readdir,
587f44794b2Sagc 	.access = fanoutfs_access,
588f44794b2Sagc 	.create = fanoutfs_create
589f44794b2Sagc };
590f44794b2Sagc 
591f44794b2Sagc int
main(int argc,char ** argv)592f44794b2Sagc main(int argc, char **argv)
593f44794b2Sagc {
594f44794b2Sagc 	int	 i;
595f44794b2Sagc 
596f44794b2Sagc 	while ((i = getopt(argc, argv, "f:v")) != -1) {
597f44794b2Sagc 		switch(i) {
598f44794b2Sagc 		case 'f':
599f44794b2Sagc 			conffile = optarg;
600f44794b2Sagc 			break;
601f44794b2Sagc 		case 'v':
602f44794b2Sagc 			verbose = 1;
603f44794b2Sagc 			break;
604f44794b2Sagc 		}
605f44794b2Sagc 	}
606f44794b2Sagc 	(void) signal(SIGHUP, sighup);
607f44794b2Sagc 	readconf(conffile);
608f44794b2Sagc 	(void) daemon(1, 1);
609*b143e0b0Sagc 	return fuse_main(argc, argv, &fanoutfs_oper, NULL);
610f44794b2Sagc }
611