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>
52 #define DEF_CONF_FILE "/etc/icfs.conf"
55 DEFINE_ARRAY(strv_t
, char *);
57 static struct stat vfs
; /* stat info of directory */
58 static virtdir_t tree
; /* virtual directory tree */
59 static int verbose
; /* how chatty are we? */
65 /********************************************************************/
67 /* convert a string to lower case */
69 strtolower(const char *path
, char *name
, size_t size
)
74 for (cp
= path
, np
= name
; (int)(np
- name
) < size
; np
++, cp
++) {
75 *np
= tolower((unsigned)*cp
);
80 /* add a name and its lower case entry */
82 add_entry(virtdir_t
*tp
, const char *name
, uint8_t type
)
84 char icname
[MAXPATHLEN
];
88 root
= virtdir_rootdir(&tree
);
90 strtolower(&name
[len
], icname
, sizeof(icname
));
91 virtdir_add(tp
, &name
[len
], strlen(name
) - len
, type
, icname
,
95 /* file system operations start here */
97 /* perform the stat operation */
99 icfs_getattr(const char *path
, struct stat
*st
)
102 char name
[MAXPATHLEN
];
104 (void) memset(st
, 0x0, sizeof(*st
));
105 if (strcmp(path
, "/") == 0) {
106 st
->st_mode
= S_IFDIR
| 0755;
110 if ((ep
= virtdir_find_tgt(&tree
, path
, strlen(path
))) == NULL
) {
113 (void) snprintf(name
, sizeof(name
), "%s/%s", virtdir_rootdir(&tree
), ep
->name
);
114 if (stat(name
, st
) < 0) {
120 /* readdir operation */
122 icfs_readdir(const char *path
, void *buf
, fuse_fill_dir_t filler
,
123 off_t offset
, struct fuse_file_info
*fi
)
127 char name
[MAXPATHLEN
];
131 if ((ep
= virtdir_find_tgt(&tree
, path
, strlen(path
))) == NULL
) {
134 (void) snprintf(name
, sizeof(name
), "%s/%s", virtdir_rootdir(&tree
), ep
->name
);
135 if ((dirp
= openvirtdir(&tree
, ep
->name
)) == NULL
) {
138 filler(buf
, ".", NULL
, 0);
139 filler(buf
, "..", NULL
, 0);
140 while ((ep
= readvirtdir(dirp
)) != NULL
) {
141 strtolower(ep
->d_name
, name
, sizeof(name
));
142 (void) filler(buf
, name
, NULL
, 0);
144 (void) closevirtdir(dirp
);
148 /* open the file in the file system */
150 icfs_open(const char *path
, struct fuse_file_info
*fi
)
155 /* read the file's contents in the file system */
157 icfs_read(const char *path
, char *buf
, size_t size
, off_t offset
,
158 struct fuse_file_info
* fi
)
161 char name
[MAXPATHLEN
];
167 if ((ep
= virtdir_find_tgt(&tree
, path
, strlen(path
))) == NULL
) {
170 (void) snprintf(name
, sizeof(name
), "%s/%s", virtdir_rootdir(&tree
), ep
->name
);
171 if ((fd
= open(name
, O_RDONLY
, 0666)) < 0) {
174 if (lseek(fd
, offset
, SEEK_SET
) < 0) {
178 if ((cc
= read(fd
, buf
, size
)) < 0) {
186 /* write the file's contents in the file system */
188 icfs_write(const char *path
, const char *buf
, size_t size
, off_t offset
,
189 struct fuse_file_info
* fi
)
192 char name
[MAXPATHLEN
];
198 if ((ep
= virtdir_find_tgt(&tree
, path
, strlen(path
))) == NULL
) {
201 (void) snprintf(name
, sizeof(name
), "%s/%s", virtdir_rootdir(&tree
), ep
->name
);
202 if ((fd
= open(name
, O_WRONLY
, 0666)) < 0) {
205 if (lseek(fd
, offset
, SEEK_SET
) < 0) {
209 if ((cc
= write(fd
, buf
, size
)) < 0) {
217 /* fill in the statvfs struct */
219 icfs_statfs(const char *path
, struct statvfs
*st
)
221 (void) memset(st
, 0x0, sizeof(*st
));
222 st
->f_bsize
= st
->f_frsize
= st
->f_iosize
= 512;
223 st
->f_owner
= vfs
.st_uid
;
228 /* "remove" a file */
230 icfs_unlink(const char *path
)
233 char name
[MAXPATHLEN
];
235 if ((ep
= virtdir_find_tgt(&tree
, path
, strlen(path
))) == NULL
) {
238 (void) snprintf(name
, sizeof(name
), "%s/%s", virtdir_rootdir(&tree
), ep
->name
);
239 if (unlink(name
) < 0) {
242 /* XXX - delete entry */
246 /* check the access on a file */
248 icfs_access(const char *path
, int acc
)
251 char name
[MAXPATHLEN
];
253 if ((ep
= virtdir_find_tgt(&tree
, path
, strlen(path
))) == NULL
) {
256 (void) snprintf(name
, sizeof(name
), "%s/%s", virtdir_rootdir(&tree
), ep
->name
);
257 if (access(name
, acc
) < 0) {
263 /* change the mode of a file */
265 icfs_chmod(const char *path
, mode_t mode
)
268 char name
[MAXPATHLEN
];
270 if ((ep
= virtdir_find_tgt(&tree
, path
, strlen(path
))) == NULL
) {
273 (void) snprintf(name
, sizeof(name
), "%s/%s", virtdir_rootdir(&tree
), ep
->name
);
274 if (chmod(name
, mode
) < 0) {
280 /* change the owner and group of a file */
282 icfs_chown(const char *path
, uid_t uid
, gid_t gid
)
285 char name
[MAXPATHLEN
];
287 if ((ep
= virtdir_find_tgt(&tree
, path
, strlen(path
))) == NULL
) {
290 (void) snprintf(name
, sizeof(name
), "%s/%s", virtdir_rootdir(&tree
), ep
->name
);
291 if (lchown(name
, uid
, gid
) < 0) {
297 /* "rename" a file */
299 icfs_rename(const char *from
, const char *to
)
302 char fromname
[MAXPATHLEN
];
303 char toname
[MAXPATHLEN
];
307 if ((ep
= virtdir_find_tgt(&tree
, from
, strlen(from
))) == NULL
) {
310 (void) snprintf(toname
, sizeof(toname
), "%s%s", dirs
.v
[0], to
);
311 if (!mkdirs(toname
)) {
314 if (rename(fromname
, toname
) < 0) {
323 icfs_create(const char *path
, mode_t mode
, struct fuse_file_info
*fi
)
327 char name
[MAXPATHLEN
];
330 if ((slash
= strrchr(path
, '/')) == NULL
) {
333 if ((ep
= virtdir_find_tgt(&tree
, path
, (int)(slash
- path
) - 1)) == NULL
) {
336 (void) snprintf(name
, sizeof(name
), "%s/%s%s", virtdir_rootdir(&tree
), ep
->name
, slash
);
337 if ((fd
= open(name
, O_RDWR
| O_CREAT
| O_EXCL
, 0666)) < 0) {
341 add_entry(&tree
, name
, 'f');
345 /* create a special node */
347 icfs_mknod(const char *path
, mode_t mode
, dev_t d
)
351 char name
[MAXPATHLEN
];
353 if ((slash
= strrchr(path
, '/')) == NULL
) {
356 if ((ep
= virtdir_find_tgt(&tree
, path
, (int)(slash
- path
) - 1)) == NULL
) {
359 (void) snprintf(name
, sizeof(name
), "%s/%s/%s", virtdir_rootdir(&tree
), ep
->name
, slash
+ 1);
360 if (mknod(name
, mode
, d
) < 0) {
363 add_entry(&tree
, name
, ((mode
& S_IFMT
) == S_IFCHR
) ? 'c' : 'b');
367 /* create a directory */
369 icfs_mkdir(const char *path
, mode_t mode
)
373 char name
[MAXPATHLEN
];
375 if ((slash
= strrchr(path
, '/')) == NULL
) {
378 if ((ep
= virtdir_find_tgt(&tree
, path
, (int)(slash
- path
) - 1)) == NULL
) {
381 (void) snprintf(name
, sizeof(name
), "%s/%s/%s", virtdir_rootdir(&tree
), ep
->name
, slash
+ 1);
382 if (mkdir(name
, mode
) < 0) {
385 add_entry(&tree
, name
, 'd');
389 /* create a symbolic link */
391 icfs_symlink(const char *path
, const char *tgt
)
395 char name
[MAXPATHLEN
];
397 if ((slash
= strrchr(path
, '/')) == NULL
) {
400 if ((ep
= virtdir_find_tgt(&tree
, path
, (int)(slash
- path
) - 1)) == NULL
) {
403 (void) snprintf(name
, sizeof(name
), "%s/%s/%s", virtdir_rootdir(&tree
), ep
->name
, slash
+ 1);
404 if (symlink(name
, tgt
) < 0) {
407 add_entry(&tree
, name
, 'l');
413 icfs_link(const char *path
, const char *tgt
)
417 char name
[MAXPATHLEN
];
419 if ((slash
= strrchr(path
, '/')) == NULL
) {
422 if ((ep
= virtdir_find_tgt(&tree
, path
, (int)(slash
- path
) - 1)) == NULL
) {
425 (void) snprintf(name
, sizeof(name
), "%s/%s/%s", virtdir_rootdir(&tree
), ep
->name
, slash
+ 1);
426 if (link(name
, tgt
) < 0) {
429 add_entry(&tree
, name
, 'f'); /* XXX */
433 /* read the contents of a symbolic link */
435 icfs_readlink(const char *path
, char *buf
, size_t size
)
438 char name
[MAXPATHLEN
];
440 if ((ep
= virtdir_find_tgt(&tree
, path
, strlen(path
))) == NULL
) {
443 (void) snprintf(name
, sizeof(name
), "%s/%s", virtdir_rootdir(&tree
), ep
->name
);
444 if (readlink(name
, buf
, size
) < 0) {
450 /* remove a directory */
452 icfs_rmdir(const char *path
)
455 char name
[MAXPATHLEN
];
457 if ((ep
= virtdir_find_tgt(&tree
, path
, strlen(path
))) == NULL
) {
460 (void) snprintf(name
, sizeof(name
), "%s/%s", virtdir_rootdir(&tree
), ep
->name
);
461 if (rmdir(name
) < 0) {
464 /* XXX - delete entry */
468 /* truncate a file */
470 icfs_truncate(const char *path
, off_t size
)
473 char name
[MAXPATHLEN
];
475 if ((ep
= virtdir_find_tgt(&tree
, path
, strlen(path
))) == NULL
) {
478 (void) snprintf(name
, sizeof(name
), "%s/%s", virtdir_rootdir(&tree
), ep
->name
);
479 if (truncate(name
, size
) < 0) {
485 /* set utimes on a file */
487 icfs_utime(const char *path
, struct utimbuf
*t
)
490 char name
[MAXPATHLEN
];
492 if ((ep
= virtdir_find_tgt(&tree
, path
, strlen(path
))) == NULL
) {
495 (void) snprintf(name
, sizeof(name
), "%s/%s", virtdir_rootdir(&tree
), ep
->name
);
496 if (utime(name
, t
) < 0) {
502 /* operations struct */
503 static struct fuse_operations icfs_oper
= {
504 .getattr
= icfs_getattr
,
505 .readlink
= icfs_readlink
,
508 .unlink
= icfs_unlink
,
510 .symlink
= icfs_symlink
,
511 .rename
= icfs_rename
,
515 .truncate
= icfs_truncate
,
520 .statfs
= icfs_statfs
,
521 .readdir
= icfs_readdir
,
522 .access
= icfs_access
,
523 .create
= icfs_create
526 /* build up a virtdir from the information in the file system */
528 dodir(virtdir_t
*tp
, char *rootdir
, const char *subdir
)
535 char icname
[MAXPATHLEN
];
536 char name
[MAXPATHLEN
];
542 (void) stat(".", &dir
);
543 (void) memcpy(&f
, &dir
, sizeof(f
));
544 f
.st_mode
= S_IFREG
| 0644;
545 (void) memcpy(&l
, &f
, sizeof(l
));
546 l
.st_mode
= S_IFLNK
| 0755;
547 virtdir_init(tp
, rootdir
, &dir
, &f
, &l
);
548 virtdir_add(tp
, "/", 1, 'd', "/", 1);
550 (void) snprintf(name
, sizeof(name
), "%s/%s", rootdir
, subdir
);
551 if ((dirp
= opendir(name
)) == NULL
) {
552 warn("dodir: can't opendir `%s'", name
);
555 len
= strlen(tp
->rootdir
);
556 while ((dp
= readdir(dirp
)) != NULL
) {
557 if (strcmp(dp
->d_name
, ".") == 0 || strcmp(dp
->d_name
, "..") == 0) {
560 (void) snprintf(name
, sizeof(name
), "%s%s%s%s%s", rootdir
, (subdir
[0] == 0x0) ? "" : "/", subdir
, "/", dp
->d_name
);
561 if (stat(name
, &st
) < 0) {
562 warnx("can't stat `%s'", name
);
565 switch (st
.st_mode
& S_IFMT
) {
585 if (!virtdir_find(tp
, &name
[len
], strlen(name
) - len
)) {
586 strtolower(&name
[len
], icname
, sizeof(icname
));
587 virtdir_add(tp
, &name
[len
], strlen(name
) - len
, type
, icname
,
591 dodir(tp
, rootdir
, &name
[len
+ 1]);
594 (void) closedir(dirp
);
599 main(int argc
, char **argv
)
603 while ((i
= getopt(argc
, argv
, "f:v")) != -1) {
613 dodir(&tree
, argv
[optind
], "");
614 return fuse_main(argc
, argv
, &icfs_oper
, NULL
);