#include <fuse_lowlevel.h>
vfprintf(stderr
, fmt
, ap
);
panic("error: no memory");
mustopen(const char *name
, const char *mode
)
if(f
= fopen(name
, mode
), f
== nil
)
panic("couldn't open file: %s", name
);
typedef struct Options Options
;
unsigned int max_idle_threads
;
#define offsetof(type, field) ((long)&((type*)0)->field)
{ t, offsetof(Options, p), 1 }
static const struct fuse_opt myopts
[] = {
OPTION("--help", show_help
),
OPTION("-V", show_version
),
OPTION("--version", show_version
),
OPTION("-d", foreground
),
OPTION("debug", foreground
),
FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP
),
FUSE_OPT_KEY("debug", FUSE_OPT_KEY_KEEP
),
OPTION("-f", foreground
),
OPTION("-s", singlethread
),
OPTION("clone_fd", clone_fd
),
OPTION("max_idle_threads=%u", max_idle_threads
),
opt_proc(void *data
, const char *arg
, int key
, struct fuse_args
*outargs
)
(void)data
; (void)outargs
;
case FUSE_OPT_KEY_NONOPT
:
if(options
.device
== nil
){
options
.device
= strdup(arg
);
if(options
.mountpoint
== nil
){
options
.mountpoint
= strdup(arg
);
" usage: asdf [options] filesystem mountpoint\n"
" -h --help print help\n"
" -V --version print version\n"
" -d -o debug enable debug output (implies -f)\n"
" -f foreground operation\n"
" -s disable multi-threaded operation\n"
" -o clone_fd use separate fuse device fd for each thread\n"
" (may improve performance)\n"
" -o max_idle_threads the maximum number of idle worker threads\n"
" allowed (default: 10)\n");
dirbuf_add(fuse_req_t req
, Dirbuf
*b
, const char *name
, fuse_ino_t ino
)
size_t oldsize
= b
->size
;
b
->size
+= fuse_add_direntry(req
, NULL
, 0, name
, NULL
, 0);
b
->p
= (char *) realloc(b
->p
, b
->size
);
memset(&stbuf
, 0, sizeof(stbuf
));
fuse_add_direntry(req
, b
->p
+ oldsize
, b
->size
- oldsize
, name
, &stbuf
,
#define min(x, y) ((x) < (y) ? (x) : (y))
reply_buf_limited(fuse_req_t req
, const char *buf
, size_t bufsize
,
off_t off
, size_t maxsize
)
return fuse_reply_buf(req
, buf
+ off
,
min(bufsize
- off
, maxsize
));
return fuse_reply_buf(req
, NULL
, 0);
vfs_getattr(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
memset(&stbuf
, 0, sizeof(stbuf
));
if(fs_stat(ino
, &stbuf
) == -1)
fuse_reply_err(req
, ENOENT
);
fuse_reply_attr(req
, &stbuf
, 1.0);
vfs_setattr(fuse_req_t req
, fuse_ino_t ino
, struct stat
*attr
, int to_set
, struct fuse_file_info
*fi
)
if(to_set
& FUSE_SET_ATTR_ATIME
)
ret
= fs_atime(ino
, attr
->st_atime
);
if(to_set
& FUSE_SET_ATTR_MTIME
)
ret
= fs_mtime(ino
, attr
->st_mtime
);
if(to_set
& FUSE_SET_ATTR_GID
)
ret
= fs_gid(ino
, attr
->st_gid
);
if(to_set
& FUSE_SET_ATTR_UID
)
ret
= fs_uid(ino
, attr
->st_uid
);
fuse_reply_err(req
, ret
);
vfs_getattr(req
, ino
, fi
);
vfs_open(fuse_req_t req
, fuse_ino_t ino
, struct fuse_file_info
*fi
)
e
= fs_open(ino
, fi
->flags
);
fuse_reply_open(req
, fi
);
vfs_read(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
off_t off
, struct fuse_file_info
*fi
)
n
= fs_read(ino
, buf
, off
, size
);
reply_buf_limited(req
, buf
, n
, off
, size
);
vfs_write(fuse_req_t req
, fuse_ino_t ino
, const char *buf
,
size_t size
, off_t off
, struct fuse_file_info
*fi
)
n
= fs_write(ino
, (void*)buf
, off
, size
);
fuse_reply_write(req
, n
);
vfs_readdir(fuse_req_t req
, fuse_ino_t ino
, size_t size
,
off_t off
, struct fuse_file_info
*fi
)
struct dirent
*dirs
, *dp
;
fuse_reply_err(req
, ENOTDIR
);
memset(&b
, 0, sizeof(b
));
for(dp
= dirs
; dp
->d_ino
; dp
++)
dirbuf_add(req
, &b
, dp
->d_name
, dp
->d_ino
);
reply_buf_limited(req
, b
.p
, b
.size
, off
, size
);
/* returns static pointer! */
lookup(uint ino
, const char *name
)
struct dirent
*dirs
, *dp
;
for(dp
= dirs
; dp
->d_ino
; dp
++)
if(strcmp(dp
->d_name
, name
) == 0){
vfs_lookup(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
struct fuse_entry_param e
;
de
= lookup(parent
, name
);
fuse_reply_err(req
, ENOENT
);
memset(&e
, 0, sizeof(e
));
/* increment ref count */
fuse_reply_entry(req
, &e
);
vfs_forget(fuse_req_t req
, fuse_ino_t ino
, uint64_t nlookup
)
printf("forgetting %d\n", nlookup
);
vfs_mknod(fuse_req_t req
, fuse_ino_t parent
, const char *name
, mode_t mode
, dev_t rdev
)
ret
= fs_mknod(parent
, name
, mode
, rdev
, nil
);
fuse_reply_err(req
, ret
);
vfs_lookup(req
, parent
, name
);
vfs_mkdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
, mode_t mode
)
ret
= fs_mkdir(parent
, name
, mode
);
fuse_reply_err(req
, ret
);
vfs_lookup(req
, parent
, name
);
vfs_unlink(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
ret
= fs_unlink(parent
, name
);
fuse_reply_err(req
, ret
);
isdirempty(struct dirent
*de
)
if(strcmp(de
->d_name
, ".") != 0 &&
strcmp(de
->d_name
, "..") != 0)
vfs_rmdir(fuse_req_t req
, fuse_ino_t parent
, const char *name
)
de
= lookup(parent
, name
);
/* this shouldn't happen */
fuse_reply_err(req
, ENOTEMPTY
);
printf("dir to delete: %d %s\n", dino
, name
);
for(de
= dir
; de
->d_ino
; de
++)
fs_unlink(dino
, de
->d_name
);
fuse_reply_err(req
, ret
);
vfs_link(fuse_req_t req
, fuse_ino_t ino
,
fuse_ino_t newparent
, const char *newname
)
ret
= fs_link(ino
, newparent
, newname
);
fuse_reply_err(req
, ret
);
vfs_lookup(req
, newparent
, newname
);
static struct fuse_lowlevel_ops hello_ll_oper
= {
fsload(const char *filename
)
FILE *f
= mustopen(filename
, "rb");
fread(fsdata
, 1, fslen
, f
);
main(int argc
, char *argv
[])
struct fuse_args args
= FUSE_ARGS_INIT(argc
, argv
);
if(fuse_opt_parse(&args
, &options
, myopts
, opt_proc
) == -1 ||
options
.device
== nil
|| options
.mountpoint
== nil
)
options
.mountpoint
= realpath(m
, nil
);
if(options
.mountpoint
== nil
)
panic("bad mount point %s", m
);
printf("device: %s\n", options
.device
);
printf("mountpoint: %s\n", options
.mountpoint
);
if(options
.show_version
){
printf("FUSE library version %s\n", fuse_pkgversion());
se
= fuse_session_new(&args
, &hello_ll_oper
,
sizeof(hello_ll_oper
), NULL
);
if(fuse_set_signal_handlers(se
) != 0)
if(fuse_session_mount(se
, options
.mountpoint
) != 0)
fuse_daemonize(options
.foreground
);
/* Block until ctrl+c or fusermount -u */
ret
= fuse_session_loop(se
);
ret
= fuse_session_loop_mt(se
, options
.clone_fd
);
fuse_session_unmount(se
);
fuse_remove_signal_handlers(se
);
fuse_session_destroy(se
);
free(options
.mountpoint
);
fuse_opt_free_args(&args
);