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