2 * Copyright © 2007 Alistair Crooks. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote
13 * products derived from this software without specific prior written
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/types.h>
51 #define DEF_CONF_FILE "/etc/fanoutfs.conf"
54 DEFINE_ARRAY(strv_t
, char *);
56 static struct stat vfs
; /* stat info of directory */
57 static strv_t dirs
; /* the directories, in order */
58 static char *conffile
; /* configuration file name */
59 static int verbose
; /* how chatty are we? */
65 /********************************************************************/
68 readconf(const char *f
)
75 if ((fp
= fopen((f
) ? f
: PREFIX DEF_CONF_FILE
, "r")) == NULL
) {
76 warn("can't read configuration file `%s'\n", f
);
79 for (line
= 1 ; fgets(buf
, sizeof(buf
), fp
) != NULL
; line
+= 1) {
80 buf
[strlen(buf
) - 1] = 0x0;
81 for (cp
= buf
; *cp
&& isspace((unsigned)*cp
) ; cp
++) {
83 if (*cp
== '\n' || *cp
== 0x0 || *cp
== '#') {
86 ALLOC(char *, dirs
.v
, dirs
.size
, dirs
.c
, 10, 10,
87 "readconf", exit(EXIT_FAILURE
));
88 dirs
.v
[dirs
.c
++] = strdup(cp
);
94 /* yes, this does too much work */
100 printf("Reading configuration file `%s'\n", conffile
);
101 for (i
= 0 ; i
< dirs
.c
; i
++) {
108 /* find the correct entry in the list of directories */
110 findentry(const char *path
, char *name
, size_t namesize
, struct stat
*sp
)
118 for (i
= 0 ; i
< dirs
.c
; i
++) {
119 (void) snprintf(name
, namesize
, "%s%s", dirs
.v
[i
], path
);
120 if (stat(name
, sp
) == 0) {
127 /* return 1 if the string `s' is present in the array */
129 present(char *s
, strv_t
*sp
)
133 for (i
= 0 ; i
< sp
->c
&& strcmp(s
, sp
->v
[i
]) != 0 ; i
++) {
138 /* make sure the directory hierarchy exists */
142 char name
[MAXPATHLEN
];
145 (void) snprintf(name
, sizeof(name
), "%s%s", dirs
.v
[0], path
);
146 slash
= &name
[strlen(path
) + 1];
147 while ((slash
= strchr(slash
, '/')) != NULL
) {
149 printf("mkdirs: dir `%s'\n", name
);
150 if (mkdir(name
, 0777) < 0) {
158 /* copy a file, preserving mode, to make it writable */
160 copyfile(char *from
, char *to
)
163 char buf
[BUFSIZ
* 10];
169 if ((fdfrom
= open(from
, O_RDONLY
, 0666)) < 0) {
170 warn("can't open file `%s' for reading", from
);
173 (void) fstat(fdfrom
, &st
);
174 if ((fdto
= open(to
, O_WRONLY
| O_CREAT
| O_EXCL
, st
.st_mode
& 07777)) < 0) {
175 warn("can't open file `%s' for reading", from
);
179 for (ret
= 1 ; ret
&& (cc
= read(fdfrom
, buf
, sizeof(buf
))) > 0 ; ) {
180 if (write(fdto
, buf
, cc
) != cc
) {
185 if (fchown(fdto
, st
.st_uid
, st
.st_gid
) < 0) {
189 (void) close(fdfrom
);
194 /* file system operations start here */
196 /* perform the stat operation */
198 fanoutfs_getattr(const char *path
, struct stat
*st
)
200 char name
[MAXPATHLEN
];
202 (void) memset(st
, 0x0, sizeof(*st
));
203 if (strcmp(path
, "/") == 0) {
204 st
->st_mode
= S_IFDIR
| 0755;
208 if (findentry(path
, name
, sizeof(name
), st
) < 0) {
214 /* readdir operation */
216 fanoutfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
217 off_t offset
, struct fuse_file_info
*fi
)
221 char name
[MAXPATHLEN
];
227 (void) memset(&names
, 0x0, sizeof(names
));
228 for (i
= 0 ; i
< dirs
.c
; i
++) {
229 (void) snprintf(name
, sizeof(name
), "%s%s", dirs
.v
[i
], path
);
230 if ((dirp
= opendir(name
)) == NULL
) {
233 while ((dp
= readdir(dirp
)) != NULL
) {
234 if (!present(dp
->d_name
, &names
)) {
235 ALLOC(char *, names
.v
, names
.size
, names
.c
,
236 10, 10, "readdir", exit(EXIT_FAILURE
));
237 names
.v
[names
.c
++] = strdup(dp
->d_name
);
240 (void) closedir(dirp
);
242 for (i
= 0 ; i
< names
.c
; i
++) {
243 (void) filler(buf
, names
.v
[i
], NULL
, 0);
252 /* open the file in the file system */
254 fanoutfs_open(const char *path
, struct fuse_file_info
*fi
)
256 char newname
[MAXPATHLEN
];
257 char name
[MAXPATHLEN
];
260 if ((d
= findentry(path
, name
, sizeof(name
), NULL
)) < 0) {
263 if (d
> 0 && (fi
->flags
& 0x3) != O_RDONLY
) {
264 /* need to copy file to writable dir */
265 (void) snprintf(newname
, sizeof(newname
), "%s%s", dirs
.v
[0], path
);
266 if (!mkdirs(newname
)) {
269 if (!copyfile(name
, newname
)) {
276 /* read the file's contents in the file system */
278 fanoutfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
279 struct fuse_file_info
* fi
)
281 char name
[MAXPATHLEN
];
287 if (findentry(path
, name
, sizeof(name
), NULL
) < 0) {
290 if ((fd
= open(name
, O_RDONLY
, 0666)) < 0) {
293 if (lseek(fd
, offset
, SEEK_SET
) < 0) {
297 if ((cc
= read(fd
, buf
, size
)) < 0) {
305 /* write the file's contents in the file system */
307 fanoutfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
308 struct fuse_file_info
* fi
)
310 char name
[MAXPATHLEN
];
316 if (findentry(path
, name
, sizeof(name
), NULL
) < 0) {
319 if ((fd
= open(name
, O_WRONLY
, 0666)) < 0) {
322 if (lseek(fd
, offset
, SEEK_SET
) < 0) {
326 if ((cc
= write(fd
, buf
, size
)) < 0) {
334 /* fill in the statvfs struct */
336 fanoutfs_statfs(const char *path
, struct statvfs
*st
)
338 (void) memset(st
, 0x0, sizeof(*st
));
339 st
->f_bsize
= st
->f_frsize
= st
->f_iosize
= 512;
340 st
->f_owner
= vfs
.st_uid
;
345 /* "remove" a file */
347 fanoutfs_unlink(const char *path
)
349 char name
[MAXPATHLEN
];
351 if (findentry(path
, name
, sizeof(name
), NULL
) < 0) {
354 if (unlink(name
) < 0) {
360 /* check the access on a file */
362 fanoutfs_access(const char *path
, int acc
)
364 char name
[MAXPATHLEN
];
366 if (findentry(path
, name
, sizeof(name
), NULL
) < 0) {
369 if (access(name
, acc
) < 0) {
375 /* change the mode of a file */
377 fanoutfs_chmod(const char *path
, mode_t mode
)
379 char name
[MAXPATHLEN
];
381 if (findentry(path
, name
, sizeof(name
), NULL
) < 0) {
384 if (chmod(name
, mode
) < 0) {
390 /* change the owner and group of a file */
392 fanoutfs_chown(const char *path
, uid_t uid
, gid_t gid
)
394 char name
[MAXPATHLEN
];
396 if (findentry(path
, name
, sizeof(name
), NULL
) < 0) {
399 if (lchown(name
, uid
, gid
) < 0) {
405 /* "rename" a file */
407 fanoutfs_rename(const char *from
, const char *to
)
409 char fromname
[MAXPATHLEN
];
410 char toname
[MAXPATHLEN
];
412 if (findentry(from
, fromname
, sizeof(fromname
), NULL
) < 0) {
415 (void) snprintf(toname
, sizeof(toname
), "%s%s", dirs
.v
[0], to
);
416 if (!mkdirs(toname
)) {
419 if (rename(fromname
, toname
) < 0) {
427 fanoutfs_create(const char *path
, mode_t mode
, struct fuse_file_info
*fi
)
430 char name
[MAXPATHLEN
];
433 if (findentry(path
, name
, sizeof(name
), &st
) >= 0) {
436 if ((fd
= open(name
, O_RDWR
| O_CREAT
| O_EXCL
, 0666)) < 0) {
443 /* create a special node */
445 fanoutfs_mknod(const char *path
, mode_t mode
, dev_t d
)
448 char name
[MAXPATHLEN
];
450 if (findentry(path
, name
, sizeof(name
), &st
) >= 0) {
453 if (mknod(name
, mode
, d
) < 0) {
459 /* create a directory */
461 fanoutfs_mkdir(const char *path
, mode_t mode
)
463 char name
[MAXPATHLEN
];
465 (void) snprintf(name
, sizeof(name
), "%s%s", dirs
.v
[0], path
);
469 if (mkdir(name
, mode
) < 0) {
475 /* create a symbolic link */
477 fanoutfs_symlink(const char *path
, const char *tgt
)
479 char name
[MAXPATHLEN
];
481 (void) snprintf(name
, sizeof(name
), "%s%s", dirs
.v
[0], path
);
485 if (symlink(name
, tgt
) < 0) {
493 fanoutfs_link(const char *path
, const char *tgt
)
495 char name
[MAXPATHLEN
];
497 (void) snprintf(name
, sizeof(name
), "%s%s", dirs
.v
[0], path
);
501 if (link(name
, tgt
) < 0) {
507 /* read the contents of a symbolic link */
509 fanoutfs_readlink(const char *path
, char *buf
, size_t size
)
511 char name
[MAXPATHLEN
];
513 if (findentry(path
, name
, sizeof(name
), NULL
) < 0) {
516 if (readlink(name
, buf
, size
) < 0) {
522 /* remove a directory */
524 fanoutfs_rmdir(const char *path
)
526 char name
[MAXPATHLEN
];
528 if (findentry(path
, name
, sizeof(name
), NULL
) < 0) {
531 if (rmdir(name
) < 0) {
537 /* truncate a file */
539 fanoutfs_truncate(const char *path
, off_t size
)
541 char name
[MAXPATHLEN
];
543 if (findentry(path
, name
, sizeof(name
), NULL
) < 0) {
546 if (truncate(name
, size
) < 0) {
552 /* set utimes on a file */
554 fanoutfs_utime(const char *path
, struct utimbuf
*t
)
556 char name
[MAXPATHLEN
];
558 if (findentry(path
, name
, sizeof(name
), NULL
) < 0) {
561 if (utime(name
, t
) < 0) {
567 /* operations struct */
568 static struct fuse_operations fanoutfs_oper
= {
569 .getattr
= fanoutfs_getattr
,
570 .readlink
= fanoutfs_readlink
,
571 .mknod
= fanoutfs_mknod
,
572 .mkdir
= fanoutfs_mkdir
,
573 .unlink
= fanoutfs_unlink
,
574 .rmdir
= fanoutfs_rmdir
,
575 .symlink
= fanoutfs_symlink
,
576 .rename
= fanoutfs_rename
,
577 .link
= fanoutfs_link
,
578 .chmod
= fanoutfs_chmod
,
579 .chown
= fanoutfs_chown
,
580 .truncate
= fanoutfs_truncate
,
581 .utime
= fanoutfs_utime
,
582 .open
= fanoutfs_open
,
583 .read
= fanoutfs_read
,
584 .write
= fanoutfs_write
,
585 .statfs
= fanoutfs_statfs
,
586 .readdir
= fanoutfs_readdir
,
587 .access
= fanoutfs_access
,
588 .create
= fanoutfs_create
592 main(int argc
, char **argv
)
596 while ((i
= getopt(argc
, argv
, "f:v")) != -1) {
606 (void) signal(SIGHUP
, sighup
);
609 return fuse_main(argc
, argv
, &fanoutfs_oper
, NULL
);