You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
4.8 KiB

#include "webfuse/adapter/impl/filesystem.h"
#include "webfuse/adapter/impl/operations.h"
#include "webfuse/adapter/impl/session.h"
#include "webfuse/core/string.h"
#include <libwebsockets.h>
#include <uuid/uuid.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
static struct fuse_lowlevel_ops const filesystem_operations =
{
.lookup = &wf_impl_operation_lookup,
.getattr = &wf_impl_operation_getattr,
.readdir = &wf_impl_operation_readdir,
.open = &wf_impl_operation_open,
.release = &wf_impl_operation_close,
.read = &wf_impl_operation_read
};
static char * wf_impl_filesystem_create_id(void)
{
uuid_t uuid;
uuid_generate(uuid);
char id[UUID_STR_LEN];
uuid_unparse(uuid, id);
return strdup(id);
}
static bool wf_impl_filesystem_is_link_broken(char const * path, char const * id)
{
bool result = false;
char buffer[UUID_STR_LEN];
ssize_t count = readlink(path, buffer, UUID_STR_LEN);
if ((0 < count) && (count < UUID_STR_LEN))
{
buffer[count] = '\0';
result = (0 == strcmp(buffer, id));
}
return result;
}
static bool wf_impl_filesystem_link_first_subdir(
char const * link_path,
char const * path)
{
bool result = false;
DIR * dir = opendir(path);
if (NULL != dir)
{
struct dirent * entry = readdir(dir);
while (NULL != entry)
{
if ((DT_DIR == entry->d_type) && ('.' != entry->d_name[0]))
{
symlink(entry->d_name, link_path);
result = true;
break;
}
entry = readdir(dir);
}
closedir(dir);
}
return result;
}
static void wf_impl_filesystem_cleanup(
struct wf_impl_filesystem * filesystem)
{
fuse_session_reset(filesystem->session);
fuse_session_unmount(filesystem->session);
fuse_session_destroy(filesystem->session);
filesystem->session = NULL;
free(filesystem->buffer.mem);
fuse_opt_free_args(&filesystem->args);
rmdir(filesystem->root_path);
if (wf_impl_filesystem_is_link_broken(filesystem->default_path, filesystem->id))
{
unlink(filesystem->default_path);
bool const success = wf_impl_filesystem_link_first_subdir(filesystem->default_path, filesystem->service_path);
if (!success)
{
rmdir(filesystem->service_path);
}
}
free(filesystem->user_data.name);
free(filesystem->id);
free(filesystem->root_path);
free(filesystem->default_path);
free(filesystem->service_path);
}
static bool wf_impl_filesystem_init(
struct wf_impl_filesystem * filesystem,
struct wf_impl_session * session,
char const * name)
{
bool result = false;
char * argv[] = {"", NULL};
filesystem->args.argc = 1;
filesystem->args.argv = argv;
filesystem->args.allocated = 0;
filesystem->user_data.session = session;
filesystem->user_data.timeout = 1.0;
filesystem->user_data.name = strdup(name);
memset(&filesystem->buffer, 0, sizeof(struct fuse_buf));
filesystem->service_path = wf_create_string("%s/%s", session->mount_point, name);
mkdir(filesystem->service_path, 0755);
filesystem->id = wf_impl_filesystem_create_id();
filesystem->root_path = wf_create_string("%s/%s/%s", session->mount_point, name, filesystem->id);
mkdir(filesystem->root_path, 0755);
filesystem->default_path = wf_create_string("%s/%s/default", session->mount_point, name);
symlink(filesystem->id, filesystem->default_path);
filesystem->session = fuse_session_new(
&filesystem->args,
&filesystem_operations,
sizeof(filesystem_operations),
&filesystem->user_data);
if (NULL != filesystem->session)
{
result = (0 == fuse_session_mount(filesystem->session, filesystem->root_path));
}
if (result)
{
lws_sock_file_fd_type fd;
fd.filefd = fuse_session_fd(filesystem->session);
struct lws_protocols const * protocol = lws_get_protocol(session->wsi);
filesystem->wsi = lws_adopt_descriptor_vhost(lws_get_vhost(session->wsi), LWS_ADOPT_RAW_FILE_DESC, fd, protocol->name, session->wsi);
if (NULL == filesystem->wsi)
{
wf_impl_filesystem_cleanup(filesystem);
result = false;
}
}
return result;
}
struct wf_impl_filesystem * wf_impl_filesystem_create(
struct wf_impl_session * session,
char const * name)
{
struct wf_impl_filesystem * filesystem = malloc(sizeof(struct wf_impl_filesystem));
if (NULL != filesystem)
{
bool success = wf_impl_filesystem_init(filesystem, session, name);
if (!success)
{
free(filesystem);
filesystem = NULL;
}
}
return filesystem;
}
void wf_impl_filesystem_dispose(
struct wf_impl_filesystem * filesystem)
{
wf_impl_filesystem_cleanup(filesystem);
free(filesystem);
}
void wf_impl_filesystem_process_request(
struct wf_impl_filesystem * filesystem)
{
int const result = fuse_session_receive_buf(filesystem->session, &filesystem->buffer);
if (0 < result)
{
fuse_session_process_buf(filesystem->session, &filesystem->buffer);
}
else if (-EINTR != result)
{
// ToDo
}
}