diff --git a/src/wsfs/operations.c b/src/wsfs/operations.c index c9f713b..e938d3d 100644 --- a/src/wsfs/operations.c +++ b/src/wsfs/operations.c @@ -1,42 +1,142 @@ #include "wsfs/operations.h" +#include #include +#include +#include +#include + +#include "wsfs/util.h" + +struct wsfs_fuse_context +{ + struct fuse_args args; + struct fuse_session * session; + struct fuse_buf buffer; + struct wsfs_operations_context user_data; + int fd; + bool mounted; +}; + +static struct fuse_lowlevel_ops const wsfs_operations = +{ + .lookup = &wsfs_operation_lookup, + .getattr = &wsfs_operation_getattr, + .readdir = &wsfs_operation_readdir, + .open = &wsfs_operation_open, + .release = &wsfs_operation_close, + .read = &wsfs_operation_read +}; + + +static bool wsfs_fuse_init( + struct wsfs_fuse_context * context, + char * mount_point, + struct wsfs_jsonrpc * rpc) +{ + bool result = false; + + char * argv[] = {"", NULL}; + context->args.argc = 1; + context->args.argv = argv; + context->args.allocated = 0; + + context->user_data.rpc = rpc; + context->user_data.timeout = 1.0; + memset(&context->buffer, 0, sizeof(struct fuse_buf)); + + context->session = fuse_session_new(&context->args, &wsfs_operations, sizeof(wsfs_operations), &context->user_data); + if (NULL != context->session) + { + result = (0 == fuse_session_mount(context->session, mount_point)); + context->fd = fuse_session_fd(context->session); + } + + // cleanup on error + if (!result) + { + if (NULL != context->session) + { + fuse_session_destroy(context->session); + context->session = NULL; + } + + free(context->buffer.mem); + fuse_opt_free_args(&context->args); + } + + return result; +} + +static void wsfs_fuse_cleanup( + struct wsfs_fuse_context * context) +{ + if (NULL != context->session) + { + fuse_session_reset(context->session); + fuse_session_unmount(context->session); + fuse_session_destroy(context->session); + context->session = NULL; + } + + free(context->buffer.mem); + fuse_opt_free_args(&context->args); +} + +static void wsfs_fuse_onreadable( + uv_poll_t* handle, + int WSFS_UNUSED_PARAM(status), + int WSFS_UNUSED_PARAM(events)) +{ + struct wsfs_fuse_context * context = handle->data; + int const result = fuse_session_receive_buf(context->session, &context->buffer); + if (0 < result) + { + fuse_session_process_buf(context->session, &context->buffer); + } + else if (-EINTR != result) + { + uv_poll_stop(handle); + } +} + +static void wsfs_fuse_oninterrupt(uv_signal_t* handle, int WSFS_UNUSED_PARAM(signum)) +{ + uv_poll_t * poll_handle = handle->data; + uv_poll_stop(poll_handle); +} int wsfs_operations_loop( char * mount_point, struct wsfs_jsonrpc * rpc) { - struct fuse_lowlevel_ops operations; - memset(&operations, 0, sizeof(struct fuse_lowlevel_ops)); - operations.lookup = &wsfs_operation_lookup; - operations.getattr = &wsfs_operation_getattr; - operations.readdir = &wsfs_operation_readdir; - operations.open = &wsfs_operation_open; - operations.release = &wsfs_operation_close; - operations.read = &wsfs_operation_read; + uv_loop_t * loop = malloc(sizeof(uv_loop_t)); + uv_loop_init(loop); - int result = 1; - const int argc = 1; - char * argv[] = {"", NULL}; - struct fuse_args args = FUSE_ARGS_INIT(argc, argv); - struct wsfs_operations_context context = { - .rpc = rpc, - .timeout = 1.0 - }; - struct fuse_session * session = fuse_session_new(&args, &operations, sizeof(operations), &context); - if (NULL != session) + struct wsfs_fuse_context context; + if (wsfs_fuse_init(&context, mount_point, rpc)) { - fuse_set_signal_handlers(session); - result = fuse_session_mount(session, mount_point); - if (0 == result) - { - result = fuse_session_loop(session); - fuse_session_unmount(session); - } - fuse_remove_signal_handlers(session); - fuse_session_destroy(session); + uv_poll_t handle; + uv_poll_init(loop, &handle, context.fd); + handle.data = &context; + uv_poll_start(&handle, UV_READABLE, &wsfs_fuse_onreadable); + + uv_signal_t signal_interrupt; + uv_signal_init(loop, &signal_interrupt); + signal_interrupt.data = &handle; + uv_signal_start_oneshot(&signal_interrupt, &wsfs_fuse_oninterrupt, SIGINT); + + uv_run(loop, UV_RUN_DEFAULT); + + uv_close((uv_handle_t*) &signal_interrupt, NULL); + uv_close((uv_handle_t*) &handle, NULL); + uv_run(loop, UV_RUN_DEFAULT); + + wsfs_fuse_cleanup(&context); } - fuse_opt_free_args(&args); + uv_loop_close(loop); + free(loop); + return 0; }