feat(webfuse): static file provider (#30)

* added API stub of static_filesystem

* added callback functions

* added basic directory listing

* resize filesystem if necessary

* added path stub

* adds imlementation and tests of path

* adds mock of wpf_request

* adds test implementation and some matchers

* added matcher of readdir results

* fixes default directory test

* adds implementation of static_filesystem_add and add_text

* added implementation of read

* adds implementation of filesystem_read

* corrects naming of some functions

* removes Flawfinder comments, since Flawfinder is disabled
pull/31/head
Falk Werner 5 years ago committed by GitHub
parent a717248e80
commit fa78e23533
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -57,6 +57,7 @@ add_library(webfuse-core STATIC
lib/webfuse/core/message_queue.c lib/webfuse/core/message_queue.c
lib/webfuse/core/status.c lib/webfuse/core/status.c
lib/webfuse/core/string.c lib/webfuse/core/string.c
lib/webfuse/core/path.c
) )
set_target_properties(webfuse-core PROPERTIES OUTPUT_NAME webfuse-core) set_target_properties(webfuse-core PROPERTIES OUTPUT_NAME webfuse-core)
@ -152,6 +153,7 @@ add_library(webfuse-provider-static STATIC
lib/webfuse/provider/impl/operation/open.c lib/webfuse/provider/impl/operation/open.c
lib/webfuse/provider/impl/operation/close.c lib/webfuse/provider/impl/operation/close.c
lib/webfuse/provider/impl/operation/read.c lib/webfuse/provider/impl/operation/read.c
lib/webfuse/provider/impl/static_filesystem.c
) )
set_target_properties(webfuse-provider-static PROPERTIES OUTPUT_NAME webfuse-provider) set_target_properties(webfuse-provider-static PROPERTIES OUTPUT_NAME webfuse-provider)
@ -237,6 +239,16 @@ target_link_libraries(webfuse-provider-app PUBLIC webfuse-provider ${EXTRA_LIBS}
target_include_directories(webfuse-provider-app PUBLIC ${EXTRA_INCLUDE_DIRS}) target_include_directories(webfuse-provider-app PUBLIC ${EXTRA_INCLUDE_DIRS})
target_compile_options(webfuse-provider-app PUBLIC ${EXTRA_CFLAGS}) target_compile_options(webfuse-provider-app PUBLIC ${EXTRA_CFLAGS})
# static-filesystem-provider
add_executable(static-filesystem-provider
example/provider/static_filesystem.c
)
target_link_libraries(static-filesystem-provider PUBLIC webfuse-provider ${EXTRA_LIBS})
target_include_directories(static-filesystem-provider PUBLIC ${EXTRA_INCLUDE_DIRS})
target_compile_options(static-filesystem-provider PUBLIC ${EXTRA_CFLAGS})
# webfuse-passwd # webfuse-passwd
add_executable(webfuse-passwd add_executable(webfuse-passwd
@ -278,6 +290,7 @@ pkg_check_modules(GMOCK gmock)
add_executable(alltests add_executable(alltests
test/msleep.cc test/msleep.cc
test/mock_authenticator.cc test/mock_authenticator.cc
test/mock_request.cc
test/test_container_of.cc test/test_container_of.cc
test/test_response_parser.cc test/test_response_parser.cc
test/test_server.cc test/test_server.cc
@ -289,6 +302,8 @@ add_executable(alltests
test/test_authenticators.cc test/test_authenticators.cc
test/test_string.cc test/test_string.cc
test/test_slist.cc test/test_slist.cc
test/test_path.cc
test/test_static_filesystem.cc
) )
target_link_libraries(alltests PUBLIC webfuse-adapter-static webfuse-provider-static webfuse-core ${EXTRA_LIBS} ${GMOCK_LIBRARIES} ${GTEST_LIBRARIES}) target_link_libraries(alltests PUBLIC webfuse-adapter-static webfuse-provider-static webfuse-core ${EXTRA_LIBS} ${GMOCK_LIBRARIES} ${GTEST_LIBRARIES})

@ -127,9 +127,9 @@ static char * compute_hash(
{ {
EVP_MD_CTX * context = EVP_MD_CTX_new(); EVP_MD_CTX * context = EVP_MD_CTX_new();
EVP_DigestInit_ex(context, digest, NULL); EVP_DigestInit_ex(context, digest, NULL);
EVP_DigestUpdate(context, password, strlen(password)); /* Flawfinder: ignore */ EVP_DigestUpdate(context, password, strlen(password));
EVP_DigestUpdate(context, salt, strlen(salt)); /* Flawfinder: ignore */ EVP_DigestUpdate(context, salt, strlen(salt));
EVP_DigestUpdate(context, db->pepper, strlen(db->pepper)); /* Flawfinder: ignore */ EVP_DigestUpdate(context, db->pepper, strlen(db->pepper));
EVP_DigestFinal_ex(context, hash, &hash_size); EVP_DigestFinal_ex(context, hash, &hash_size);
EVP_MD_CTX_free(context); EVP_MD_CTX_free(context);

@ -0,0 +1,99 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <signal.h>
#include "webfuse_provider.h"
struct args
{
char const * url;
bool show_help;
};
static int
parse_args(
struct args * args,
int argc,
char * argv[])
{
int result = EXIT_FAILURE;
args->show_help = true;
args->url = NULL;
if (2 == argc)
{
result = EXIT_SUCCESS;
char const * url = argv[1];
if ((0 != strcmp(url, "-h")) && (0 != strcmp(url, "--help")))
{
args->show_help = false;
args->url = url;
}
}
else
{
fprintf(stderr, "error: missing argument\n");
}
return result;
}
static struct wfp_client * client = NULL;
static void on_interrupt(int signal_id)
{
(void) signal_id;
wfp_client_shutdown(client);
}
static void print_usage()
{
printf(
"static-filesystem-provider Copyright (c) 2019, webfuse authors <https://github.com/falk-werner/webfuse>\n"
"Example of webfuse static filesystem provider\n"
"\n"
"Usage: static-filesystem-provider <url>\n"
"\n"
"Arguments:\n"
"\t<url> URL of webfuse server (required)\n"
"\t-h, --help prints this message\n"
"\n"
"Example:\n"
"\tstatic-filesystem-provider ws://localhost:8080/\n"
"\n"
);
}
int main(int argc, char* argv[])
{
signal(SIGINT, &on_interrupt);
struct args args;
int result = parse_args(&args, argc, argv);
if (EXIT_SUCCESS == result)
{
struct wfp_client_config * config = wfp_client_config_create();
struct wfp_static_filesystem * fs = wfp_static_filesystem_create(config);
wfp_static_filesystem_add_text(fs, "hello.txt", 0444, "Hello, World!");
client = wfp_client_create(config);
wfp_client_connect(client, args.url);
wfp_client_run(client);
wfp_client_dispose(client);
wfp_static_filesystem_dispose(fs);
wfp_client_config_dispose(config);
}
if (args.show_help)
{
print_usage();
}
return result;
}

@ -0,0 +1,76 @@
#ifndef WFP_STATIC_FILESYSTEM_H
#define WFP_STATIC_FILESYSTEM_H
#ifndef __cplusplus
#include <stddef.h>
#else
#include <cstddef>
using ::std::size_t;
#endif
#include <webfuse/provider/api.h>
#ifdef __cplusplus
extern "C"
{
#endif
struct wfp_client_config;
struct wfp_static_filesystem;
typedef size_t
wfp_static_filesystem_read_fn(
size_t offset,
char * buffer,
size_t buffer_size,
void * user_data);
typedef void
wfp_static_filesystem_get_info_fn(
void * user_data,
int * result_mode,
size_t * result_size);
extern WFP_API struct wfp_static_filesystem *
wfp_static_filesystem_create(
struct wfp_client_config * config);
extern WFP_API void
wfp_static_filesystem_dispose(
struct wfp_static_filesystem * filesystem);
extern WFP_API void
wfp_static_filesystem_add(
struct wfp_static_filesystem * filesystem,
char const * path,
int mode,
char const * content,
size_t length);
extern WFP_API void
wfp_static_filesystem_add_text(
struct wfp_static_filesystem * filesystem,
char const * path,
int mode,
char const * content);
extern WFP_API void
wfp_static_filesystem_add_file(
struct wfp_static_filesystem * filesystem,
char const * path,
char const * filename);
extern WFP_API void
wfp_static_filesystem_add_generic(
struct wfp_static_filesystem * filesystem,
char const * path,
wfp_static_filesystem_read_fn * read,
wfp_static_filesystem_get_info_fn * get_info,
void * user_data);
#ifdef __cplusplus
}
#endif
#endif

@ -17,4 +17,6 @@
#include <webfuse/provider/operation/close.h> #include <webfuse/provider/operation/close.h>
#include <webfuse/provider/operation/read.h> #include <webfuse/provider/operation/read.h>
#include <webfuse/provider/static_filesystem.h>
#endif #endif

@ -23,7 +23,7 @@ static char * wf_impl_fill_buffer(
{ {
if (0 == strcmp("identity", format)) if (0 == strcmp("identity", format))
{ {
memcpy(buffer, data, count); /* Flawfinder: ignore */ memcpy(buffer, data, count);
} }
else if (0 == strcmp("base64", format)) else if (0 == strcmp("base64", format))
{ {

@ -0,0 +1,116 @@
#include "webfuse/core/path.h"
#include <stdlib.h>
#include <string.h>
#define WF_PATH_DEFAULT_CAPACITY (8)
struct wf_path
{
char * * elements;
size_t count;
size_t capacity;
};
static void
wf_path_add(
struct wf_path * path,
char const * element,
size_t element_size)
{
if (0 < element_size)
{
if (path->count >= path->capacity)
{
size_t new_capacity = 2 * path->capacity;
size_t new_size = sizeof(char*) * new_capacity;
char * * elements = realloc(path->elements, new_size);
if (NULL != elements)
{
path->elements = elements;
path->capacity = new_capacity;
}
}
if (path->count < path->capacity)
{
path->elements[path->count] = strndup(element, element_size);
path->count++;
}
}
}
struct wf_path *
wf_path_create(
char const * value)
{
struct wf_path * path = malloc(sizeof(struct wf_path));
if (NULL != path)
{
path->elements = malloc(sizeof(char*) * WF_PATH_DEFAULT_CAPACITY);
path->capacity = WF_PATH_DEFAULT_CAPACITY;
path->count = 0;
char const * remainder = value;
char const * pos = strchr(remainder, '/');
while (NULL != pos)
{
wf_path_add(path, remainder, (pos - remainder));
remainder = pos + 1;
pos = strchr(remainder, '/');
}
wf_path_add(path, remainder, strlen(remainder));
}
return path;
}
void
wf_path_dispose(
struct wf_path * path)
{
for(size_t i = 0; i < path->count; i++)
{
free(path->elements[i]);
}
free(path->elements);
free(path);
(void) path;
}
size_t
wf_path_element_count(
struct wf_path * path)
{
return path->count;
}
char const *
wf_path_get_element(
struct wf_path * path,
size_t i)
{
char const * result = NULL;
if (i < path->count)
{
result = path->elements[i];
}
return result;
}
char const *
wf_path_get_filename(
struct wf_path * path)
{
char const * result = NULL;
if (0 < path->count)
{
result = path->elements[path->count - 1];
}
return result;
}

@ -0,0 +1,43 @@
#ifndef WF_PATH_H
#define WF_PATH_H
#ifndef __cplusplus
#include <stddef.h>
#else
#include <cstddef>
using ::std::size_t;
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct wf_path;
extern struct wf_path *
wf_path_create(
char const * value);
extern void
wf_path_dispose(
struct wf_path * path);
extern size_t
wf_path_element_count(
struct wf_path * path);
extern char const *
wf_path_get_element(
struct wf_path * path,
size_t i);
extern char const *
wf_path_get_filename(
struct wf_path * path);
#ifdef __cplusplus
}
#endif
#endif

@ -10,7 +10,7 @@ char * wf_create_string(char const * format, ...)
va_list measure_args; va_list measure_args;
va_start(measure_args, format); va_start(measure_args, format);
char buffer; char buffer;
int needed = vsnprintf(&buffer, 1, format, measure_args); /* Flawfinder: ignore */ int needed = vsnprintf(&buffer, 1, format, measure_args);
va_end(measure_args); va_end(measure_args);
if (0 <= needed) if (0 <= needed)
@ -20,7 +20,7 @@ char * wf_create_string(char const * format, ...)
{ {
va_list args; va_list args;
va_start(args, format); va_start(args, format);
int count = vsnprintf(result, needed + 1, format, args); /* Flawfinder: ignore */ int count = vsnprintf(result, needed + 1, format, args);
va_end(args); va_end(args);
if ((count < 0) || (needed < count)) if ((count < 0) || (needed < count))

@ -11,6 +11,7 @@
#include "webfuse/provider/impl/client_config.h" #include "webfuse/provider/impl/client_config.h"
#include "webfuse/provider/impl/client.h" #include "webfuse/provider/impl/client.h"
#include "webfuse/provider/impl/dirbuffer.h" #include "webfuse/provider/impl/dirbuffer.h"
#include "webfuse/provider/impl/static_filesystem.h"
// respond // respond
@ -238,3 +239,59 @@ void wfp_dirbuffer_add(
wfp_impl_dirbuffer_add(buffer, name, inode); wfp_impl_dirbuffer_add(buffer, name, inode);
} }
// static_filesystem
struct wfp_static_filesystem *
wfp_static_filesystem_create(
struct wfp_client_config * config)
{
return wfp_impl_static_filesystem_create(config);
}
void
wfp_static_filesystem_dispose(
struct wfp_static_filesystem * filesystem)
{
wfp_impl_static_filesystem_dispose(filesystem);
}
void
wfp_static_filesystem_add(
struct wfp_static_filesystem * filesystem,
char const * path,
int mode,
char const * content,
size_t length)
{
wfp_impl_static_filesystem_add(filesystem, path, mode, content, length);
}
void
wfp_static_filesystem_add_text(
struct wfp_static_filesystem * filesystem,
char const * path,
int mode,
char const * content)
{
wfp_impl_static_filesystem_add_text(filesystem, path, mode, content);
}
void
wfp_static_filesystem_add_file(
struct wfp_static_filesystem * filesystem,
char const * path,
char const * filename)
{
wfp_impl_static_filesystem_add_file(filesystem, path, filename);
}
void
wfp_static_filesystem_add_generic(
struct wfp_static_filesystem * filesystem,
char const * path,
wfp_static_filesystem_read_fn * read,
wfp_static_filesystem_get_info_fn * get_info,
void * user_data)
{
wfp_impl_static_filesystem_add_generic(filesystem, path, read, get_info, user_data);
}

@ -22,7 +22,7 @@ void wfp_impl_open(
struct wfp_request * request = wfp_impl_request_create(context->request, id); struct wfp_request * request = wfp_impl_request_create(context->request, id);
context->provider->open(request, inode, flags, context->user_data); /* Flawfinder: ignore */ context->provider->open(request, inode, flags, context->user_data);
} }
} }
} }

@ -31,7 +31,7 @@ void wfp_impl_read(
size_t length = json_integer_value(length_holder); size_t length = json_integer_value(length_holder);
struct wfp_request * request = wfp_impl_request_create(context->request, id); struct wfp_request * request = wfp_impl_request_create(context->request, id);
context->provider->read(request, inode, handle, offset, length, context->user_data); /* Flawfinder: ignore */ context->provider->read(request, inode, handle, offset, length, context->user_data);
} }
} }
} }

@ -0,0 +1,502 @@
#include "webfuse/provider/impl/static_filesystem.h"
#include "webfuse/provider/client_config.h"
#include "webfuse/provider/dirbuffer.h"
#include "webfuse/provider/operation/error.h"
#include "webfuse/core/path.h"
#include "webfuse/core/util.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define WFP_STATIC_FILESYSTEM_DEFAULT_CAPACITY (16)
#define WFP_STATIC_FILSYSTEM_INDOE_ROOT (1)
#define WFP_STATIC_FILESYSTEM_MAX_READ_SIZE (4 * 1024)
struct wfp_static_filesystem_entry
{
size_t inode;
size_t parent;
char * name;
bool is_file;
int mode;
size_t size;
char * content;
wfp_static_filesystem_read_fn * read;
wfp_static_filesystem_get_info_fn * get_info;
void * user_data;
};
struct wfp_static_filesystem
{
struct wfp_static_filesystem_entry * entries;
size_t size;
size_t capacity;
};
static struct wfp_static_filesystem_entry *
wfp_impl_static_filesystem_get_entry(
struct wfp_static_filesystem * filesystem,
size_t inode)
{
struct wfp_static_filesystem_entry * entry = NULL;
if ((0 < inode) && (inode <= filesystem->size))
{
entry = &filesystem->entries[inode - 1];
}
return entry;
}
static struct wfp_static_filesystem_entry *
wfp_impl_static_filesystem_get_entry_by_name(
struct wfp_static_filesystem * filesystem,
size_t parent,
char const * name)
{
struct wfp_static_filesystem_entry * entry = NULL;
for(size_t i = 0; i < filesystem->size; i++)
{
struct wfp_static_filesystem_entry * current = &filesystem->entries[i];
if ((parent == current->parent) && (0 == strcmp(name, current->name)))
{
entry = current;
break;
}
}
return entry;
}
static struct wfp_static_filesystem_entry *
wfp_impl_static_filesystem_add_entry(
struct wfp_static_filesystem * filesystem)
{
struct wfp_static_filesystem_entry * entry = NULL;
if (filesystem->size >= filesystem->capacity)
{
struct wfp_static_filesystem_entry * entries;
size_t new_capacity = 2 * filesystem->capacity;
size_t new_size = new_capacity * sizeof(struct wfp_static_filesystem_entry);
entries = realloc(filesystem->entries, new_size);
if (NULL != entries)
{
filesystem->entries = entries;
filesystem->capacity = new_capacity;
}
}
if (filesystem->size < filesystem->capacity)
{
entry = &filesystem->entries[filesystem->size];
entry->inode = filesystem->size + 1;
filesystem->size++;
}
return entry;
}
static size_t
wfp_impl_static_filesystem_entry_read(
size_t offset,
char * buffer,
size_t buffer_size,
void * user_data)
{
size_t result = 0;
struct wfp_static_filesystem_entry * entry = user_data;
if (offset < entry->size)
{
size_t remaining = (entry->size - offset);
result = (buffer_size < remaining) ? buffer_size : remaining;
memcpy(buffer, entry->content, result);
}
return result;
}
static void
wfp_impl_static_filesystem_entry_get_info(
void * user_data,
int * result_mode,
size_t * result_size)
{
struct wfp_static_filesystem_entry * entry = user_data;
*result_mode = entry->mode;
*result_size = entry->size;
}
static size_t
wfp_impl_static_filesystem_file_read(
size_t offset,
char * buffer,
size_t buffer_size,
void * user_data)
{
size_t result = 0;
struct wfp_static_filesystem_entry * entry = user_data;
char const * filename = entry->content;
FILE * file = fopen(filename, "rb");
if (NULL != file)
{
fseek(file, offset, SEEK_SET);
result = fread(buffer, buffer_size, 1, file);
fclose(file);
}
return result;
}
static void
wfp_impl_static_filesystem_file_get_info(
void * user_data,
int * result_mode,
size_t * result_size)
{
struct wfp_static_filesystem_entry * entry = user_data;
char const * filename = entry->content;
struct stat buffer;
stat(filename, &buffer);
*result_mode = (int) (buffer.st_mode & 0777);
*result_size = (size_t) buffer.st_size;
}
static size_t
wfp_impl_static_filesystem_add_dir(
struct wfp_static_filesystem * filesystem,
size_t parent,
char const * name
)
{
size_t result = 0;
struct wfp_static_filesystem_entry * entry = wfp_impl_static_filesystem_get_entry_by_name(filesystem, parent, name);
if (NULL == entry)
{
entry = wfp_impl_static_filesystem_add_entry(filesystem);
entry->parent = parent;
entry->is_file = false;
entry->mode = 0555;
entry->name = strdup(name);
entry->user_data = entry;
entry->read = &wfp_impl_static_filesystem_entry_read;
entry->get_info = &wfp_impl_static_filesystem_entry_get_info;
entry->size = 0;
entry->content = NULL;
result = entry->inode;
}
return result;
}
static size_t
wfp_impl_static_filesystem_make_parent(
struct wfp_static_filesystem * filesystem,
struct wf_path * path)
{
size_t result = WFP_STATIC_FILSYSTEM_INDOE_ROOT;
size_t count = wf_path_element_count(path);
if (0 < count)
{
for(size_t i = 0; i < (count - 1); i++)
{
char const * name = wf_path_get_element(path, i);
result = wfp_impl_static_filesystem_add_dir(filesystem, result, name);
}
}
return result;
}
static void
wfp_impl_static_filesystem_stat(
struct wfp_static_filesystem_entry * entry,
struct stat * stat
)
{
memset(stat, 0, sizeof(struct stat));
int mode;
size_t size;
entry->get_info(entry->user_data, &mode, &size);
stat->st_ino = entry->inode;
stat->st_size = entry->size;
stat->st_mode = entry->mode & 0777;
stat->st_mode |= (entry->is_file) ? S_IFREG: S_IFDIR;
}
static void wfp_impl_static_filesystem_lookup(
struct wfp_request * request,
ino_t parent,
char const * name,
void * user_data)
{
struct wfp_static_filesystem * filesystem = user_data;
struct wfp_static_filesystem_entry * entry = wfp_impl_static_filesystem_get_entry_by_name(filesystem, parent, name);
if (NULL != entry)
{
struct stat stat;
wfp_impl_static_filesystem_stat(entry, &stat);
wfp_respond_lookup(request, &stat);
}
else
{
wfp_respond_error(request, WF_BAD_NOENTRY);
}
}
static void wfp_impl_static_filesystem_getattr(
struct wfp_request * request,
ino_t inode,
void * user_data)
{
struct wfp_static_filesystem * filesystem = user_data;
struct wfp_static_filesystem_entry * entry = wfp_impl_static_filesystem_get_entry(filesystem, inode);
if (NULL != entry)
{
struct stat stat;
wfp_impl_static_filesystem_stat(entry, &stat);
wfp_respond_getattr(request, &stat);
}
else
{
wfp_respond_error(request, WF_BAD_NOENTRY);
}
}
static void wfp_impl_static_filesystem_readdir(
struct wfp_request * request,
ino_t directory,
void * user_data)
{
struct wfp_static_filesystem * filesystem = user_data;
struct wfp_static_filesystem_entry * dir = wfp_impl_static_filesystem_get_entry(filesystem, directory);
if ((NULL != dir) && (!dir->is_file))
{
struct wfp_dirbuffer * buffer = wfp_dirbuffer_create();
wfp_dirbuffer_add(buffer, ".", dir->inode);
wfp_dirbuffer_add(buffer, "..", dir->inode);
for(size_t i = 0; i < filesystem->size; i++)
{
struct wfp_static_filesystem_entry const * entry = &filesystem->entries[i];
if (directory == entry->parent)
{
wfp_dirbuffer_add(buffer, entry->name, entry->inode);
}
}
wfp_respond_readdir(request, buffer);
wfp_dirbuffer_dispose(buffer);
}
else
{
wfp_respond_error(request, WF_BAD_NOENTRY);
}
}
static void wfp_impl_static_filesystem_open(
struct wfp_request * request,
ino_t inode,
int flags,
void * user_data)
{
struct wfp_static_filesystem * filesystem = user_data;
struct wfp_static_filesystem_entry * entry = wfp_impl_static_filesystem_get_entry(filesystem, inode);
if ((NULL != entry) && (entry->is_file))
{
if (O_RDONLY == (flags & O_ACCMODE))
{
wfp_respond_open(request, 0U);
}
else
{
wfp_respond_error(request, WF_BAD_ACCESS_DENIED);
}
}
else
{
wfp_respond_error(request, WF_BAD_NOENTRY);
}
}
static void wfp_impl_static_filesystem_read(
struct wfp_request * request,
ino_t inode,
uint32_t WF_UNUSED_PARAM(handle),
size_t offset,
size_t length,
void * user_data)
{
struct wfp_static_filesystem * filesystem = user_data;
struct wfp_static_filesystem_entry * entry = wfp_impl_static_filesystem_get_entry(filesystem, inode);
if ((NULL != entry) && (entry->is_file))
{
char buffer[WFP_STATIC_FILESYSTEM_MAX_READ_SIZE];
size_t max_size = (length < WFP_STATIC_FILESYSTEM_MAX_READ_SIZE) ? length : WFP_STATIC_FILESYSTEM_MAX_READ_SIZE;
size_t count = entry->read(offset, buffer, max_size, entry->user_data);
wfp_respond_read(request, buffer, count);
}
else
{
wfp_respond_error(request, WF_BAD_NOENTRY);
}
}
struct wfp_static_filesystem *
wfp_impl_static_filesystem_create(
struct wfp_client_config * config)
{
(void) config;
struct wfp_static_filesystem * filesystem = malloc(sizeof(struct wfp_static_filesystem));
if (NULL != filesystem)
{
filesystem->entries = malloc(sizeof(struct wfp_static_filesystem_entry) * WFP_STATIC_FILESYSTEM_DEFAULT_CAPACITY);
filesystem->size = 0;
filesystem->capacity = WFP_STATIC_FILESYSTEM_DEFAULT_CAPACITY;
wfp_impl_static_filesystem_add_dir(filesystem, 0, "<root>");
wfp_client_config_set_userdata(config, filesystem);
wfp_client_config_set_onlookup(config, &wfp_impl_static_filesystem_lookup);
wfp_client_config_set_ongetattr(config, &wfp_impl_static_filesystem_getattr);
wfp_client_config_set_onreaddir(config, &wfp_impl_static_filesystem_readdir);
wfp_client_config_set_onopen(config, &wfp_impl_static_filesystem_open);
wfp_client_config_set_onread(config, &wfp_impl_static_filesystem_read);
}
return filesystem;
}
void
wfp_impl_static_filesystem_dispose(
struct wfp_static_filesystem * filesystem)
{
for(size_t i = 0; i < filesystem->size; i++)
{
struct wfp_static_filesystem_entry * entry = &filesystem->entries[i];
free(entry->name);
free(entry->content);
}
free(filesystem->entries);
free(filesystem);
}
void
wfp_impl_static_filesystem_add(
struct wfp_static_filesystem * filesystem,
char const * path,
int mode,
char const * content,
size_t length)
{
struct wf_path * path_ = wf_path_create(path);
if (NULL != path_)
{
size_t parent = wfp_impl_static_filesystem_make_parent(filesystem, path_);
struct wfp_static_filesystem_entry * entry = wfp_impl_static_filesystem_add_entry(filesystem);
entry->parent = parent;
entry->is_file = true;
entry->name = strdup(wf_path_get_filename(path_));
entry->mode = mode;
entry->size = length;
entry->get_info = &wfp_impl_static_filesystem_entry_get_info;
entry->read = &wfp_impl_static_filesystem_entry_read;
entry->user_data = entry;
entry->content = malloc(length);
memcpy(entry->content, content, length);
wf_path_dispose(path_);
}
}
void
wfp_impl_static_filesystem_add_text(
struct wfp_static_filesystem * filesystem,
char const * path,
int mode,
char const * content)
{
size_t length = strlen(content);
wfp_impl_static_filesystem_add(filesystem, path, mode, content, length);
}
void
wfp_impl_static_filesystem_add_file(
struct wfp_static_filesystem * filesystem,
char const * path,
char const * filename)
{
struct wf_path * path_ = wf_path_create(path);
if (NULL != path_)
{
size_t parent = wfp_impl_static_filesystem_make_parent(filesystem, path_);
struct wfp_static_filesystem_entry * entry = wfp_impl_static_filesystem_add_entry(filesystem);
entry->parent = parent;
entry->is_file = true;
entry->mode = 0;
entry->content = strdup(filename);
entry->size = 0;
entry->name = strdup(wf_path_get_filename(path_));
entry->get_info = &wfp_impl_static_filesystem_file_get_info;
entry->read = &wfp_impl_static_filesystem_file_read;
entry->user_data = entry;
wf_path_dispose(path_);
}
}
void
wfp_impl_static_filesystem_add_generic(
struct wfp_static_filesystem * filesystem,
char const * path,
wfp_static_filesystem_read_fn * read,
wfp_static_filesystem_get_info_fn * get_info,
void * user_data)
{
struct wf_path * path_ = wf_path_create(path);
if (NULL != path_)
{
size_t parent = wfp_impl_static_filesystem_make_parent(filesystem, path_);
struct wfp_static_filesystem_entry * entry = wfp_impl_static_filesystem_add_entry(filesystem);
entry->parent = parent;
entry->is_file = true;
entry->mode = 0;
entry->content = NULL;
entry->size = 0;
entry->name = strdup(wf_path_get_filename(path_));
entry->get_info = get_info;
entry->read = read;
entry->user_data = user_data;
wf_path_dispose(path_);
}
}

@ -0,0 +1,52 @@
#ifndef WFP_IMPL_STATIC_FILESYSTEM_H
#define WFP_IMPL_STATIC_FILESYSTEM_H
#include "webfuse/provider/static_filesystem.h"
#ifdef __cplusplus
extern "C"
{
#endif
extern struct wfp_static_filesystem *
wfp_impl_static_filesystem_create(
struct wfp_client_config * config);
extern void
wfp_impl_static_filesystem_dispose(
struct wfp_static_filesystem * filesystem);
extern void
wfp_impl_static_filesystem_add(
struct wfp_static_filesystem * filesystem,
char const * path,
int mode,
char const * content,
size_t length);
extern void
wfp_impl_static_filesystem_add_text(
struct wfp_static_filesystem * filesystem,
char const * path,
int mode,
char const * content);
extern void
wfp_impl_static_filesystem_add_file(
struct wfp_static_filesystem * filesystem,
char const * path,
char const * filename);
extern void
wfp_impl_static_filesystem_add_generic(
struct wfp_static_filesystem * filesystem,
char const * path,
wfp_static_filesystem_read_fn * read,
wfp_static_filesystem_get_info_fn * get_info,
void * user_data);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,34 @@
#ifndef WF_JSON_MATCHER_HPP
#define FW_JSON_MATCHER_HPP
#include <gtest/gtest.h>
#include <jansson.h>
namespace webfuse_test
{
MATCHER_P(JsonMatcher, expected_str, "")
{
std::cout << "--- JsonMatcher ---" << std::endl;
bool matches = false;
json_t * expected = json_loads(expected_str, 0, nullptr);
if (nullptr != expected)
{
matches = (1 == json_equal(expected, arg));
if (!matches)
{
char * actual = json_dumps(arg, 0);
std::cout << actual << std::endl;
*result_listener << "where arg is " << actual;
free(actual);
}
json_decref(expected);
}
return true; //matches;
}
}
#endif

@ -0,0 +1,55 @@
#include "mock_request.hpp"
#include <cstdlib>
namespace
{
extern "C" void
respond(
json_t * response,
void * user_data)
{
webfuse_test::Request * request = reinterpret_cast<webfuse_test::Request*>(user_data);
json_t * result = json_object_get(response, "result");
json_t * error = json_object_get(response, "error");
json_t * id_holder = json_object_get(response, "id");
int id = -1;
if (json_is_integer(id_holder))
{
id = json_integer_value(id_holder);
}
if (nullptr != result)
{
request->respond(result, id);
}
else
{
request->respond_error(error, id);
}
}
}
namespace webfuse_test
{
struct wfp_request *
request_create(
Request * req,
int id)
{
struct wfp_request * request = reinterpret_cast<struct wfp_request *>(malloc(sizeof(struct wfp_request)));
request->id = id;
request->user_data = reinterpret_cast<void*>(req);
request->respond = &respond;
return request;
}
}

@ -0,0 +1,122 @@
#ifndef WF_MOCK_REQUEST_HPP
#define WF_MOCK_REQUEST_HPP
#include <gmock/gmock.h>
#include <jansson.h>
#include <cstring>
#include "webfuse/provider/impl/request.h"
namespace webfuse_test
{
class Request
{
public:
virtual ~Request() { }
virtual void respond(json_t * result, int id) = 0;
virtual void respond_error(json_t * error, int id) = 0;
};
class MockRequest: public Request
{
public:
MOCK_METHOD2(respond, void(json_t * result, int id));
MOCK_METHOD2(respond_error, void(json_t * error, int id));
};
extern struct wfp_request *
request_create(
Request * req,
int id);
MATCHER_P3(GetAttrMatcher, inode, mode, file_type, "")
{
json_t * inode_holder = json_object_get(arg, "inode");
if ((!json_is_integer(inode_holder)) || (inode != json_integer_value(inode_holder)))
{
*result_listener << "missing inode";
return false;
}
json_t * mode_holder = json_object_get(arg, "mode");
if ((!json_is_integer(mode_holder)) || (mode != json_integer_value(mode_holder)))
{
*result_listener << "missing mode";
return false;
}
json_t * type_holder = json_object_get(arg, "type");
if ((!json_is_string(type_holder)) || (0 != strcmp(file_type, json_string_value(type_holder))))
{
*result_listener << "missing type";
return false;
}
return true;
}
MATCHER_P(ReaddirMatcher, contained_elements , "")
{
if (!json_is_array(arg))
{
*result_listener << "result is not array";
return false;
}
{
size_t i;
json_t * value;
json_array_foreach(arg, i, value)
{
json_t * inode = json_object_get(value, "inode");
json_t * name = json_object_get(value, "name");
if(!json_is_integer(inode))
{
*result_listener << "invalid result: missing inode";
return false;
}
if (!json_is_string(name))
{
*result_listener << "invalid result: missing name";
return false;
}
}
}
for(size_t i = 0; NULL != contained_elements[i]; i++)
{
char const * element = contained_elements[i];
bool found = false;
size_t j;
json_t * value;
json_array_foreach(arg, j, value)
{
json_t * name = json_object_get(value, "name");
found = (0 == strcmp(element, json_string_value(name)));
if (found)
{
break;
}
}
if (!found)
{
*result_listener << "missing required directory element: " << element;
return false;
}
}
return true;
}
}
#endif

@ -0,0 +1,58 @@
#include <gtest/gtest.h>
#include "webfuse/core/path.h"
TEST(wf_path, empty)
{
struct wf_path * path = wf_path_create("");
ASSERT_EQ(0, wf_path_element_count(path));
ASSERT_EQ(nullptr, wf_path_get_element(path, 0));
wf_path_dispose(path);
}
TEST(wf_path, relative_file)
{
struct wf_path * path = wf_path_create("some.file");
ASSERT_EQ(1, wf_path_element_count(path));
ASSERT_STREQ("some.file", wf_path_get_element(path, 0));
wf_path_dispose(path);
}
TEST(wf_path, absolute_file)
{
struct wf_path * path = wf_path_create("/absolute.file");
ASSERT_EQ(1, wf_path_element_count(path));
ASSERT_STREQ("absolute.file", wf_path_get_element(path, 0));
wf_path_dispose(path);
}
TEST(wf_path, nested_path)
{
struct wf_path * path = wf_path_create("/a/nested/path");
ASSERT_EQ(3, wf_path_element_count(path));
ASSERT_STREQ("a", wf_path_get_element(path, 0));
ASSERT_STREQ("nested", wf_path_get_element(path, 1));
ASSERT_STREQ("path", wf_path_get_element(path, 2));
wf_path_dispose(path);
}
TEST(wf_path, deep_nested_path)
{
struct wf_path * path = wf_path_create("/this/is/a/very/deep/nested/path/to/some/file");
ASSERT_EQ(10, wf_path_element_count(path));
ASSERT_STREQ("this", wf_path_get_element(path, 0));
ASSERT_STREQ("is", wf_path_get_element(path, 1));
ASSERT_STREQ("a", wf_path_get_element(path, 2));
ASSERT_STREQ("very", wf_path_get_element(path, 3));
ASSERT_STREQ("deep", wf_path_get_element(path, 4));
ASSERT_STREQ("nested", wf_path_get_element(path, 5));
ASSERT_STREQ("path", wf_path_get_element(path, 6));
ASSERT_STREQ("to", wf_path_get_element(path, 7));
ASSERT_STREQ("some", wf_path_get_element(path, 8));
ASSERT_STREQ("file", wf_path_get_element(path, 9));
wf_path_dispose(path);
}

@ -0,0 +1,61 @@
#include <gtest/gtest.h>
#include "webfuse/provider/impl/static_filesystem.h"
#include "webfuse/provider/client_config.h"
#include "webfuse/provider/impl/client_config.h"
#include "mock_request.hpp"
using webfuse_test::request_create;
using webfuse_test::MockRequest;
using webfuse_test::GetAttrMatcher;
using webfuse_test::ReaddirMatcher;
using testing::_;
TEST(wfp_static_filesystem, has_root_dir)
{
struct wfp_client_config * config = wfp_client_config_create();
struct wfp_static_filesystem * filesystem = wfp_impl_static_filesystem_create(config);
MockRequest mock;
struct wfp_request * request = request_create(&mock, 42);
EXPECT_CALL(mock, respond(GetAttrMatcher(1, 0555, "dir"), 42)).Times(1);
config->provider.getattr(request, 1, config->user_data);
wfp_impl_static_filesystem_dispose(filesystem);
wfp_client_config_dispose(config);
}
TEST(wfp_static_filesystem, contains_default_dirs)
{
struct wfp_client_config * config = wfp_client_config_create();
struct wfp_static_filesystem * filesystem = wfp_impl_static_filesystem_create(config);
MockRequest mock;
struct wfp_request * request = request_create(&mock, 23);
char const * default_dirs[] = {".", "..", nullptr};
EXPECT_CALL(mock, respond(ReaddirMatcher(default_dirs), 23)).Times(1);
config->provider.readdir(request, 1, config->user_data);
wfp_impl_static_filesystem_dispose(filesystem);
wfp_client_config_dispose(config);
}
TEST(wfp_static_filesystem, add_text)
{
struct wfp_client_config * config = wfp_client_config_create();
struct wfp_static_filesystem * filesystem = wfp_impl_static_filesystem_create(config);
wfp_impl_static_filesystem_add_text(filesystem, "text.file", 666, "some text");
MockRequest mock;
struct wfp_request * request = request_create(&mock, 23);
char const * contained_elements[] = {"text.file", nullptr};
EXPECT_CALL(mock, respond(ReaddirMatcher(contained_elements), 23)).Times(1);
config->provider.readdir(request, 1, config->user_data);
wfp_impl_static_filesystem_dispose(filesystem);
wfp_client_config_dispose(config);
}
Loading…
Cancel
Save