Merge pull request #1 from falk-werner/master

upstream update
pull/66/head
nosamad 4 years ago committed by GitHub
commit 76a0469f40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -2,15 +2,15 @@
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
labels: 'bug'
assignees: ''
---
**Describe the bug**
**Description**
A clear and concise description of what the bug is.
**To Reproduce**
**Steps To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
@ -20,19 +20,5 @@ Steps to reproduce the behavior:
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: \[e.g. iOS\]
- Browser \[e.g. chrome, safari\]
- Version \[e.g. 22\]
**Smartphone (please complete the following information):**
- Device: \[e.g. iPhone6\]
- OS: \[e.g. iOS8.1\]
- Browser \[e.g. stock browser, safari\]
- Version \[e.g. 22\]
**Additional context**
Add any other context about the problem here.

3
.gitignore vendored

@ -2,3 +2,6 @@
/.build/
/.deps/
/.settings/language.settings.xml
/doc/api
/subprojects/*
!/subprojects/*.wrap

@ -12,17 +12,18 @@ addons:
- qemu-user-static
env:
global:
- DISTRO=ubuntu
- PARALLELMFLAGS="-j4"
- PORTABLE_WORSPACE=1
matrix:
- BUILDTYPE=Debug MARCH=amd64 CHECK_TARGET=memcheck
- BUILDTYPE=Release MARCH=amd64 CHECK_TARGET=memcheck
- BUILDTYPE=Debug MARCH=arm32v7 CHECK_TARGET=check
- BUILDTYPE=MinSizeRel MARCH=arm32v7 CHECK_TARGET=check
- DISTRO=ubuntu BUILDTYPE=Debug MARCH=amd64 CHECK_TARGET=memcheck
- DISTRO=ubuntu BUILDTYPE=Coverage MARCH=amd64 CHECK_TARGET=check
- DISTRO=ubuntu BUILDTYPE=Release MARCH=amd64 CHECK_TARGET=memcheck
- DISTRO=ubuntu BUILDTYPE=Debug MARCH=arm32v7 CHECK_TARGET=check
- DISTRO=ubuntu BUILDTYPE=MinSizeRel MARCH=arm32v7 CHECK_TARGET=check
- DISTRO=alpine BUILDTYPE=Debug MARCH=amd64 CHECK_TARGET=check
before_script:
- make BUILDTYPE=$BUILDTYPE MARCH=$MARCH
script:
- make BUILDTYPE=$BUILDTYPE MARCH=$MARCH $CHECK_TARGET
- make DISTRO=$DISTRO BUILDTYPE=$BUILDTYPE MARCH=$MARCH $CHECK_TARGET
after_success:
- bash <(curl -s https://codecov.io/bash)

@ -1,348 +1,63 @@
cmake_minimum_required (VERSION 3.10)
project(webfuse VERSION 0.2.0 DESCRIPTION "Websocket filesystem based on libfuse")
project(webfuse VERSION 0.3.0 DESCRIPTION "Websocket filesystem based on libfuse")
option(WITHOUT_TESTS "disable unit tests" OFF)
option(WITHOUT_EXAMPLE "disable example" OFF)
option(WITHOUT_TESTS "disable unit tests" OFF)
option(WITHOUT_ADAPTER "disable adapter library" OFF)
option(WITHOUT_PROVIDER "disable provider library" OFF)
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(coverage)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_package(PkgConfig REQUIRED)
pkg_check_modules(FUSE3 REQUIRED fuse3)
pkg_check_modules(LWS REQUIRED libwebsockets)
pkg_check_modules(JANSSON REQUIRED jansson)
pkg_check_modules(UUID REQUIRED uuid)
add_definitions(-D_FILE_OFFSET_BITS=64)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(C_WARNINGS -Wall -Wextra)
set(C_WARNINGS -Wall -Wextra -Werror)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
add_definitions(
-pg
--coverage
-fprofile-arcs
-ftest-coverage
)
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
link_libraries(gcov)
else()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
endif()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs")
endif()
include_directories(
"include"
${FUSE3_INCLUDE_DIRS}
${LWS_INCLUDE_DIRS}
${JANSSON_INCLUDE_DIRS}
${UUID_INCLUDE_DIRS}
)
set(EXTRA_LIBS
${EXTRA_LIBS}
${FUSE3_LIBRARIES}
${LWS_LIBRARIES}
${JANSSON_LIBRARIES}
${UUID_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
)
add_compile_options(
${C_WARNINGS}
${FUSE3_CFLAGS_OTHER}
${LWS_CFLAGS_OTHER}
${JANSSON_CFLAGS_OTHER}
${UUID_CFLAGS_OTHER}
"-pthread"
)
# libwebfuse-core
add_library(webfuse-core STATIC
lib/webfuse/core/slist.c
lib/webfuse/core/message.c
lib/webfuse/core/message_queue.c
lib/webfuse/core/status.c
lib/webfuse/core/string.c
lib/webfuse/core/path.c
lib/webfuse/core/lws_log.c
)
set_target_properties(webfuse-core PROPERTIES OUTPUT_NAME webfuse-core)
target_include_directories(webfuse-core PUBLIC lib)
set_target_properties(webfuse-core PROPERTIES C_VISIBILITY_PRESET hidden)
install(DIRECTORY include/webfuse/core DESTINATION include/webfuse)
# libwebfuse-adapter
add_library(webfuse-adapter-static STATIC
lib/webfuse/adapter/api.c
lib/webfuse/adapter/impl/filesystem.c
lib/webfuse/adapter/impl/server.c
lib/webfuse/adapter/impl/server_config.c
lib/webfuse/adapter/impl/server_protocol.c
lib/webfuse/adapter/impl/session.c
lib/webfuse/adapter/impl/session_manager.c
lib/webfuse/adapter/impl/authenticator.c
lib/webfuse/adapter/impl/authenticators.c
lib/webfuse/adapter/impl/credentials.c
lib/webfuse/adapter/impl/operations.c
lib/webfuse/adapter/impl/time/timepoint.c
lib/webfuse/adapter/impl/time/timer.c
lib/webfuse/adapter/impl/time/timeout_manager.c
lib/webfuse/adapter/impl/operation/lookup.c
lib/webfuse/adapter/impl/operation/getattr.c
lib/webfuse/adapter/impl/operation/readdir.c
lib/webfuse/adapter/impl/operation/open.c
lib/webfuse/adapter/impl/operation/close.c
lib/webfuse/adapter/impl/operation/read.c
lib/webfuse/adapter/impl/jsonrpc/proxy.c
lib/webfuse/adapter/impl/jsonrpc/server.c
lib/webfuse/adapter/impl/jsonrpc/method.c
lib/webfuse/adapter/impl/jsonrpc/request.c
lib/webfuse/adapter/impl/jsonrpc/response.c
lib/webfuse/adapter/impl/jsonrpc/util.c
)
set_target_properties(webfuse-adapter-static PROPERTIES OUTPUT_NAME webfuse-adapter)
set_target_properties(webfuse-adapter-static PROPERTIES C_VISIBILITY_PRESET hidden)
target_include_directories(webfuse-adapter-static PUBLIC lib)
add_library(webfuse-adapter SHARED
lib/webfuse/adapter/api.c
)
set_target_properties(webfuse-adapter PROPERTIES VERSION ${PROJECT_VERSION})
set_target_properties(webfuse-adapter PROPERTIES SOVERSION 0)
set_target_properties(webfuse-adapter PROPERTIES C_VISIBILITY_PRESET hidden)
set_target_properties(webfuse-adapter PROPERTIES COMPILE_DEFINITIONS "WF_API=WF_EXPORT")
target_link_libraries(webfuse-adapter PRIVATE webfuse-adapter-static webfuse-core)
file(WRITE "${PROJECT_BINARY_DIR}/libwebfuse-adapter.pc"
"prefix=\"${CMAKE_INSTALL_PREFIX}\"
exec_prefix=\${prefix}
libdir=\${exec_prefix}/lib${LIB_SUFFIX}
includedir=\${prefix}/include
Name: libwebfuse
Description: Websockets filesystem server library
Version: ${PROJECT_VERSION}
Libs: -L\${libdir} -lwebfuse-adapter -l${FUSE3_LIBRARIES} -l${LWS_LIBRARIES} -l${JANSSON_LIBRARIES}
Cflags: -I\${includedir}"
)
install(TARGETS webfuse-adapter DESTINATION lib${LIB_SUFFIX})
install(FILES include/webfuse_adapter.h DESTINATION include)
install(DIRECTORY include/webfuse/adapter DESTINATION include/webfuse)
install(FILES "${PROJECT_BINARY_DIR}/libwebfuse-adapter.pc" DESTINATION lib${LIB_SUFFIX}/pkgconfig)
#libwebfuse-provider
add_library(webfuse-provider-static STATIC
lib/webfuse/provider/api.c
lib/webfuse/provider/impl/url.c
lib/webfuse/provider/impl/client.c
lib/webfuse/provider/impl/client_config.c
lib/webfuse/provider/impl/client_protocol.c
lib/webfuse/provider/impl/provider.c
lib/webfuse/provider/impl/request.c
lib/webfuse/provider/impl/dirbuffer.c
lib/webfuse/provider/impl/operation/lookup.c
lib/webfuse/provider/impl/operation/getattr.c
lib/webfuse/provider/impl/operation/readdir.c
lib/webfuse/provider/impl/operation/open.c
lib/webfuse/provider/impl/operation/close.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 C_VISIBILITY_PRESET hidden)
target_include_directories(webfuse-provider-static PUBLIC lib)
add_library(webfuse-provider SHARED
lib/webfuse/provider/api.c
)
set_target_properties(webfuse-provider PROPERTIES VERSION ${PROJECT_VERSION})
set_target_properties(webfuse-provider PROPERTIES SOVERSION 0)
set_target_properties(webfuse-provider PROPERTIES C_VISIBILITY_PRESET hidden)
set_target_properties(webfuse-provider PROPERTIES COMPILE_DEFINITIONS "WFP_API=WFP_EXPORT")
target_include_directories(webfuse-provider PUBLIC lib)
target_link_libraries(webfuse-provider PRIVATE webfuse-provider-static webfuse-core)
file(WRITE "${PROJECT_BINARY_DIR}/libwebfuse-provider.pc"
"prefix=\"${CMAKE_INSTALL_PREFIX}\"
exec_prefix=\${prefix}
libdir=\${exec_prefix}/lib${LIB_SUFFIX}
includedir=\${prefix}/include
Name: libwebfuse-provider
Description: Provider library for websockets filesystem
Version: ${PROJECT_VERSION}
Libs: -L\${libdir} -lwebfuse-provider -l${LWS_LIBRARIES} -l${JANSSON_LIBRARIES}
Cflags: -I\${includedir}"
)
install(TARGETS webfuse-provider DESTINATION lib${LIB_SUFFIX})
install(FILES include/webfuse_provider.h DESTINATION include)
install(DIRECTORY include/webfuse/provider DESTINATION include/webfuse)
install(FILES "${PROJECT_BINARY_DIR}/libwebfuse-provider.pc" DESTINATION lib${LIB_SUFFIX}/pkgconfig)
# examples
pkg_check_modules(OPENSSL REQUIRED openssl)
include(webfuse_core)
include(webfuse_adapter)
include(webfuse_provider)
include(unit_tests)
if(NOT WITHOUT_EXAMPLE)
set(CPACK_SOURCE_GENERATOR "TGZ")
set(CPACK_GENERATOR "DEB")
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}")
set(CPACK_DESCRIPTION "Websocket filesystem based on libfuse")
#set(CPACK_COMPONENTS_ALL libraries)
set(CPACK_DEB_COMPONENT_INSTALL ON)
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Falk Werner")
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
# libuserdb
set(CPACK_DEBIAN_LIBRARIES_FILE_NAME "webfuse_${PROJECT_VERSION}_${CMAKE_SYSTEM_NAME}.deb")
set(CPACK_DEBIAN_LIBRARIES_PACKAGE_NAME "webfuse")
add_library(userdb STATIC
example/lib/userdb/src/userdb.c
)
target_include_directories(userdb PUBLIC
example/lib/userdb/include
${OPENSSL_INCLUDE_DIRS}
${JANSSON_INCLUDE_DIRS}
)
target_compile_options(userdb PUBLIC ${OPENSSL_CFLAGS_OTHER})
# daemon
add_executable(webfused
example/daemon/main.c
)
target_link_libraries(webfused PUBLIC webfuse-adapter userdb ${OPENSSL_LIBRARIES} ${EXTRA_LIBS})
target_compile_options(webfused PUBLIC ${OPENSSL_CFLAGS_OTHER})
# provider
add_executable(webfuse-provider-app
example/provider/main.c
)
set_target_properties(webfuse-provider-app PROPERTIES OUTPUT_NAME webfuse-provider)
target_link_libraries(webfuse-provider-app PUBLIC webfuse-provider ${EXTRA_LIBS})
target_include_directories(webfuse-provider-app PUBLIC ${EXTRA_INCLUDE_DIRS})
# 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
add_executable(webfuse-passwd
example/passwd/main.c
)
target_link_libraries(webfuse-passwd PUBLIC
userdb
${OPENSSL_LIBRARIES}
${JANSSON_LIBRARIES}
)
target_include_directories(webfuse-passwd PUBLIC
example/passwd
example/lib/userdb/include
${OPENSSL_INCLUDE_DIRS}
${JANSSON_INCLUDE_DIRS}
)
target_compile_options(webfuse-passwd PUBLIC ${OPENSSL_CFLAGS_OTHER})
endif(NOT WITHOUT_EXAMPLE)
# tests
if(NOT WITHOUT_TESTS)
include (CTest)
pkg_check_modules(GTEST gtest_main)
include(GoogleTest)
pkg_check_modules(GMOCK gmock)
add_executable(alltests
test/msleep.cc
test/die_if.cc
test/mock_authenticator.cc
test/mock_request.cc
test/core/test_container_of.cc
test/core/test_string.cc
test/core/test_slist.cc
test/core/test_path.cc
test/core/test_status.cc
test/core/test_message.cc
test/core/test_message_queue.cc
test/adapter/test_response_parser.cc
test/adapter/test_server.cc
test/adapter/test_timepoint.cc
test/adapter/test_timer.cc
test/adapter/test_credentials.cc
test/adapter/test_authenticator.cc
test/adapter/test_authenticators.cc
test/adapter/test_fuse_req.cc
test/adapter/jsonrpc/test_util.cc
test/adapter/jsonrpc/test_is_request.cc
test/adapter/jsonrpc/test_request.cc
test/adapter/jsonrpc/test_is_response.cc
test/adapter/jsonrpc/test_response.cc
test/adapter/jsonrpc/test_server.cc
test/adapter/jsonrpc/test_proxy.cc
test/provider/test_url.cc
test/provider/test_static_filesystem.cc
test/integration/test_integration.cc
test/integration/server.cc
test/integration/provider.cc
)
target_link_libraries(alltests PUBLIC webfuse-adapter-static webfuse-provider-static webfuse-core ${EXTRA_LIBS} ${GMOCK_LIBRARIES} ${GTEST_LIBRARIES})
target_include_directories(alltests PUBLIC test lib ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS})
target_compile_options(alltests PUBLIC ${GMOCK_CFLAGS} ${GTEST_CFLAGS})
enable_testing()
gtest_discover_tests(alltests TEST_PREFIX alltests:)
add_custom_target(coverage
./alltests
COMMAND mkdir -p coverage
COMMAND lcov --capture --directory . --output-file coverage/lcov.info
COMMAND lcov --remove coverage/lcov.info '/usr/*' --output-file coverage/lcov.info
COMMAND lcov --remove coverage/lcov.info '*/test/*' --output-file coverage/lcov.info
)
add_dependencies(coverage alltests)
add_custom_target(coverage-report
COMMAND genhtml coverage/lcov.info --output-directory coverage/report
)
add_dependencies(coverage-report coverage)
set(CPACK_DEBIAN_HEADERS_FILE_NAME "webfuse-dev_${PROJECT_VERSION}_${CMAKE_SYSTEM_NAME}.deb")
set(CPACK_DEBIAN_HEADERS_PACKAGE_NAME "webfuse-dev")
set(CPACK_DEBIAN_HEADERS_PACKAGE_DEPENDS "webfuse")
endif(NOT WITHOUT_TESTS)
include(CPack)

@ -0,0 +1,333 @@
# Doxyfile 1.8.13
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "webfuse"
PROJECT_NUMBER = 0.3.0
PROJECT_BRIEF = "Websocket filesystem based on libfuse"
PROJECT_LOGO =
OUTPUT_DIRECTORY = "doc/api"
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = NO
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
ALIASES =
TCL_SUBST =
OPTIMIZE_OUTPUT_FOR_C = YES
OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO
EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 0
AUTOLINK_SUPPORT = YES
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
GROUP_NESTED_COMPOUNDS = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
TYPEDEF_HIDES_STRUCT = NO
LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = YES
EXTRACT_PRIVATE = NO
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = YES
EXTRACT_LOCAL_METHODS = NO
EXTRACT_ANON_NSPACES = NO
HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO
HIDE_FRIEND_COMPOUNDS = NO
HIDE_IN_BODY_DOCS = NO
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
HIDE_COMPOUND_REFERENCE= NO
SHOW_INCLUDE_FILES = YES
SHOW_GROUPED_MEMB_INC = NO
FORCE_LOCAL_INCLUDES = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = NO
SORT_MEMBERS_CTORS_1ST = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = YES
GENERATE_TESTLIST = YES
GENERATE_BUGLIST = YES
GENERATE_DEPRECATEDLIST= YES
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_FILES = YES
SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
LAYOUT_FILE =
CITE_BIB_FILES =
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = YES
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_AS_ERROR = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = README.md \
doc/build.md doc/protocol.md doc/api.md \
include
INPUT_ENCODING = UTF-8
FILE_PATTERNS = *.h
RECURSIVE = YES
EXCLUDE =
EXCLUDE_SYMLINKS = NO
EXCLUDE_PATTERNS =
EXCLUDE_SYMBOLS =
EXAMPLE_PATH =
EXAMPLE_PATTERNS = *
EXAMPLE_RECURSIVE = NO
IMAGE_PATH =
INPUT_FILTER =
FILTER_PATTERNS =
FILTER_SOURCE_FILES = NO
FILTER_SOURCE_PATTERNS =
USE_MDFILE_AS_MAINPAGE = README.md
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = YES
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = NO
REFERENCED_BY_RELATION = NO
REFERENCES_RELATION = NO
REFERENCES_LINK_SOURCE = YES
SOURCE_TOOLTIPS = YES
USE_HTAGS = NO
VERBATIM_HEADERS = YES
CLANG_ASSISTED_PARSING = NO
CLANG_OPTIONS =
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = YES
COLS_IN_ALPHA_INDEX = 5
IGNORE_PREFIX = wf_ wfp_
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = NO
HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 100
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
DOCSET_PUBLISHER_NAME = Publisher
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = NO
GENERATE_QHP = NO
QCH_FILE =
QHP_NAMESPACE = org.doxygen.Project
QHP_VIRTUAL_FOLDER = doc
QHP_CUST_FILTER_NAME =
QHP_CUST_FILTER_ATTRS =
QHP_SECT_FILTER_ATTRS =
QHG_LOCATION =
GENERATE_ECLIPSEHELP = NO
ECLIPSE_DOC_ID = org.doxygen.Project
DISABLE_INDEX = NO
GENERATE_TREEVIEW = NO
ENUM_VALUES_PER_LINE = 4
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
FORMULA_FONTSIZE = 10
FORMULA_TRANSPARENT = YES
USE_MATHJAX = NO
MATHJAX_FORMAT = HTML-CSS
MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
MATHJAX_EXTENSIONS =
MATHJAX_CODEFILE =
SEARCHENGINE = YES
SERVER_BASED_SEARCH = NO
EXTERNAL_SEARCH = NO
SEARCHENGINE_URL =
SEARCHDATA_FILE = searchdata.xml
EXTERNAL_SEARCH_ID =
EXTRA_SEARCH_MAPPINGS =
#---------------------------------------------------------------------------
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
GENERATE_LATEX = NO
LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex
COMPACT_LATEX = NO
PAPER_TYPE = a4
EXTRA_PACKAGES =
LATEX_HEADER =
LATEX_FOOTER =
LATEX_EXTRA_STYLESHEET =
LATEX_EXTRA_FILES =
PDF_HYPERLINKS = YES
USE_PDFLATEX = YES
LATEX_BATCHMODE = NO
LATEX_HIDE_INDICES = NO
LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
GENERATE_RTF = NO
RTF_OUTPUT = rtf
COMPACT_RTF = NO
RTF_HYPERLINKS = NO
RTF_STYLESHEET_FILE =
RTF_EXTENSIONS_FILE =
RTF_SOURCE_CODE = NO
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
GENERATE_MAN = NO
MAN_OUTPUT = man
MAN_EXTENSION = .3
MAN_SUBDIR =
MAN_LINKS = NO
#---------------------------------------------------------------------------
# Configuration options related to the XML output
#---------------------------------------------------------------------------
GENERATE_XML = NO
XML_OUTPUT = xml
XML_PROGRAMLISTING = YES
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
GENERATE_DOCBOOK = NO
DOCBOOK_OUTPUT = docbook
DOCBOOK_PROGRAMLISTING = NO
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
GENERATE_PERLMOD = NO
PERLMOD_LATEX = NO
PERLMOD_PRETTY = YES
PERLMOD_MAKEVAR_PREFIX =
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = NO
EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
PREDEFINED =
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration options related to external references
#---------------------------------------------------------------------------
TAGFILES =
GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = YES
EXTERNAL_PAGES = YES
PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = YES
MSCGEN_PATH =
DIA_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
DOT_NUM_THREADS = 0
DOT_FONTNAME = Helvetica
DOT_FONTSIZE = 10
DOT_FONTPATH =
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES
UML_LOOK = NO
UML_LIMIT_NUM_FIELDS = 10
TEMPLATE_RELATIONS = NO
INCLUDE_GRAPH = YES
INCLUDED_BY_GRAPH = YES
CALL_GRAPH = NO
CALLER_GRAPH = NO
GRAPHICAL_HIERARCHY = YES
DIRECTORY_GRAPH = YES
DOT_IMAGE_FORMAT = png
INTERACTIVE_SVG = NO
DOT_PATH =
DOTFILE_DIRS =
MSCFILE_DIRS =
DIAFILE_DIRS =
PLANTUML_JAR_PATH =
PLANTUML_CFG_FILE =
PLANTUML_INCLUDE_PATH =
DOT_GRAPH_MAX_NODES = 50
MAX_DOT_GRAPH_DEPTH = 0
DOT_TRANSPARENT = NO
DOT_MULTI_TARGETS = NO
GENERATE_LEGEND = YES
DOT_CLEANUP = YES

@ -36,7 +36,7 @@ CONTAINER_USER ?= user
CONTAINER_GROUP ?= user
UBUNTU_CODENAME ?= bionic
DEBIAN_CODENAME ?= testing-slim
ALPINE_CODENAME ?= 3.9
SKIP_MD5SUM ?= $(call filter_out_command,md5sum)
SKIP_MD5SUM := $(SKIP_MD5SUM)
@ -50,23 +50,23 @@ FETCH_TARGETS += $(FETCHDIR)/dumb-init-$(DUMB_INIT_VERSION).tar.gz
$(FETCHDIR)/dumb-init-$(DUMB_INIT_VERSION).tar.gz: URL := https://github.com/Yelp/dumb-init/archive/v${DUMB_INIT_VERSION}.tar.gz
$(SKIP_MD5SUM)$(FETCHDIR)/dumb-init-$(DUMB_INIT_VERSION).tar.gz: MD5 := 6166084b05772cdcf615a762c6f3b32e
GTEST_VERSION ?= 1.8.1
GTEST_VERSION ?= 1.10.0
DOCKER_BUILDARGS += GTEST_VERSION=$(GTEST_VERSION)
FETCH_TARGETS += $(FETCHDIR)/googletest-release-$(GTEST_VERSION).tar.gz
$(FETCHDIR)/googletest-release-$(GTEST_VERSION).tar.gz: URL := https://github.com/google/googletest/archive/release-$(GTEST_VERSION).tar.gz
$(SKIP_MD5SUM)$(FETCHDIR)/googletest-release-$(GTEST_VERSION).tar.gz: MD5 := 2e6fbeb6a91310a16efe181886c59596
$(SKIP_MD5SUM)$(FETCHDIR)/googletest-release-$(GTEST_VERSION).tar.gz: MD5 := ecd1fa65e7de707cd5c00bdac56022cd
FUSE_VERSION ?= 3.1.1
FUSE_VERSION ?= 3.9.1
DOCKER_BUILDARGS += FUSE_VERSION=$(FUSE_VERSION)
FETCH_TARGETS += $(FETCHDIR)/libfuse-fuse-$(FUSE_VERSION).tar.gz
$(FETCHDIR)/libfuse-fuse-$(FUSE_VERSION).tar.gz: URL := https://github.com/libfuse/libfuse/archive/fuse-$(FUSE_VERSION).tar.gz
$(SKIP_MD5SUM)$(FETCHDIR)/libfuse-fuse-$(FUSE_VERSION).tar.gz: MD5 := 097f194856938afdd98bea1a5c046edd
$(SKIP_MD5SUM)$(FETCHDIR)/libfuse-fuse-$(FUSE_VERSION).tar.gz: MD5 := 5f7c1062def710d8b60343524a18cc82
WEBSOCKETS_VERSION ?= 3.1.0
WEBSOCKETS_VERSION ?= 4.0.10
DOCKER_BUILDARGS += WEBSOCKETS_VERSION=$(WEBSOCKETS_VERSION)
FETCH_TARGETS += $(FETCHDIR)/libwebsockets-$(WEBSOCKETS_VERSION).tar.gz
$(FETCHDIR)/libwebsockets-$(WEBSOCKETS_VERSION).tar.gz: URL := https://github.com/warmcat/libwebsockets/archive/v$(WEBSOCKETS_VERSION).tar.gz
$(SKIP_MD5SUM)$(FETCHDIR)/libwebsockets-$(WEBSOCKETS_VERSION).tar.gz: MD5 := 325359a25d5f6d22725ff5d086db1c76
$(SKIP_MD5SUM)$(FETCHDIR)/libwebsockets-$(WEBSOCKETS_VERSION).tar.gz: MD5 := a1ce5a279fd06b2ce132c02c292df7aa
JANSSON_VERSION ?= 2.12
DOCKER_BUILDARGS += JANSSON_VERSION=$(JANSSON_VERSION)
@ -74,27 +74,27 @@ FETCH_TARGETS += $(FETCHDIR)/jansson-$(JANSSON_VERSION).tar.gz
$(FETCHDIR)/jansson-$(JANSSON_VERSION).tar.gz: URL := https://github.com/akheron/jansson/archive/v$(JANSSON_VERSION).tar.gz
$(SKIP_MD5SUM)$(FETCHDIR)/jansson-$(JANSSON_VERSION).tar.gz: MD5 := c4b106528d5ffb521178565de1ba950d
QEMU_VERSION ?= v3.1.0-2
QEMU_VERSION ?= v4.1.0-1
DOCKER_BUILDARGS += QEMU_VERSION_=$(QEMU_VERSION)
FETCH_TARGETS += $(FETCHDIR)/qemu-arm-static-$(QEMU_VERSION)
$(FETCHDIR)/qemu-arm-static-$(QEMU_VERSION): URL := https://github.com/multiarch/qemu-user-static/releases/download/$(QEMU_VERSION)/qemu-arm-static
$(SKIP_MD5SUM)$(FETCHDIR)/qemu-arm-static-$(QEMU_VERSION): MD5 := 8ebd24e63fdfa07c557d45373bd831b1
$(SKIP_MD5SUM)$(FETCHDIR)/qemu-arm-static-$(QEMU_VERSION): MD5 := e508e6e4dd7f3a851207aac245a4653f
#######################################################################################################################
# Architecture-specific rule target configuration
CMAKE_TARGETS += amd64-ubuntu-builder
CMAKE_TARGETS += amd64-debian-builder
CMAKE_TARGETS += amd64-alpine-builder
CMAKE_TARGETS += arm32v7-ubuntu-builder
CMAKE_TARGETS += arm32v7-debian-builder
CMAKE_TARGETS += arm32v7-alpine-builder
MEMCHECK_FILTER = $(call regex_march_distro,'$(HOST_MARCH)','.*')
UBUNTU_FILTER = $(call regex_march_distro,'.*','ubuntu')
UBUNTU_TARGETS = $(addprefix $(OUTDIR)/docker/,$(call filter_targets,$(UBUNTU_FILTER),$(TARGETS)))
DEBIAN_FILTER = $(call regex_march_distro,'.*','debian')
DEBIAN_TARGETS = $(addprefix $(OUTDIR)/docker/,$(call filter_targets,$(DEBIAN_FILTER),$(TARGETS)))
ALPINE_FILTER = $(call regex_march_distro,'.*','alpine')
ALPINE_TARGETS = $(addprefix $(OUTDIR)/docker/,$(call filter_targets,$(ALPINE_FILTER),$(TARGETS)))
#######################################################################################################################
# Common rule target configuration
@ -138,7 +138,7 @@ $(CHECK_TARGETS): GOALS := test
$(UBUNTU_TARGETS): CODENAME := $(UBUNTU_CODENAME)
$(DEBIAN_TARGETS): CODENAME := $(DEBIAN_CODENAME)
$(ALPINE_TARGETS): CODENAME := $(ALPINE_CODENAME)
$(FETCH_TARGETS): | $(FETCHDIR)
$(SILENT)$(call curl,$@,$(URL),$(MD5))

@ -9,11 +9,10 @@ webfuse combines libwebsockets and libfuse. It allows ot attach a remote filesys
## Contents
- [Motivation](#Motivation)
- [Fellow Repositories](#Fellow-Repositories)
- [Concept](#Concept)
- [Similar Projects](#Similar-Projects)
- [API](#API)
- [Build and run](#Build-and-run)
- [Dependencies](#Dependencies)
- [Further Documentation](#Further-Documentation)
## Motivation
@ -32,6 +31,12 @@ To avoid Steps 1 and 2, it would be great to keep the update file entirely in we
webfuse solves this problem by using the [WebSocket](https://en.wikipedia.org/wiki/WebSocket) protocol. The emdedded device runs a service, known as webfuse adapter, awaiting incoming connections, e.g. from a web browser. The browser acts as a file system provider, providing the update file to the device.
## Fellow Repositories
- **[webfuse-example](https://github.com/falk-werner/webfuse-example)**: Example of webfuse
- **[webfused](https://github.com/falk-werner/webfused)**: Reference implementation of webfuse daemon
- **[webfuse-provider](https://github.com/falk-werner/webfuse-provider)**: Reference implementation of webfuse provider
## Concept
![concept](doc/concept.png)
@ -46,27 +51,14 @@ A reference implementation of such a daemon is provided within the examples. The
- Whenever the user makes filesystem requests, such as *ls*, the request is redirected via webfuse daemon to the connected filesystem provider
Currently all requests are initiated by webfuse daemon and responded by filesystem provider. This may change in future, e.g. when authentication is supported.
### Filesystem represenation
![filesystem](doc/filesystem.png)
To handle multiple filesystems, that are registered by one or more providers, webfuse daemon maintains a directory structure as shown above.
- **mount_point** is the entry point of the drectory structure
- **fwupdate** is a name defined by the provider when filesystem was registered
*Note: the picture above shows two providers, where both registered a filesystem named "fwupdate"*
### Adapters and Providers
- **&lt;uuid&gt;** is the filesystem id choosen by webfuse daemon to distinguish different filesystems
In webfuse, an adapter is a component that adapts the libfuse API to a websocket interface.
Currently, libwebfuse implements only a server based adapter - a websocket server, that allows clients to connect a remote file system which
is represented via libfuse on the server side.
- **default** is a symbolic link maintained by webfuse daemon to identify the default filesystem
This directoy structure allows to handle multiple filesystems registered by multiple providers.
It can be used as a kind of service registry, where each filesystem represents a service.
The named subdirectores distinguish differend service types. The symbolic link *default* can be used to identify the
default service and the listing of a named subdirectory can be used to list available services of a particular type.
In webfuse, a provider is a component that provides a filesystem via websocket interface.
Currently, libwebfuse implements only a client based provider - a websocket client that provides a local filesystem to a remote server.
## Similar Projects
@ -76,378 +68,8 @@ default service and the listing of a named subdirectory can be used to list avai
Unlike webfuse, davfs2 mounts a remote filesystem locally, that is provided by a WebDAV server. In contrast, webfuse starts a server awaiting client connections to attach the remote file system.
## API
### Requests, responses and notifications
There are three types of messages, used for communication between webfuse daemon and filesystem provider. All message types are encoded in [JSON](https://www.json.org/) and strongly inspired by [JSON-RPC](https://www.jsonrpc.org/).
#### Request
A request is used by a sender to invoke a method on the receiver. The sender awaits a response from the receiver. Since requests and responses can be sendet or answered in any order, an id is provided in each request to identify it.
{
"method": <method_name>,
"params": <params>,
"id" : <id>
}
| Item | Data type | Description |
| ----------- |:---------:| --------------------------------- |
| method_name | string | name of the method to invoke |
| params | array | method specific parameters |
| id | integer | id, which is repeated in response |
#### Response
A response is used to answer a prior request. There are two kinds of responses:
##### Successful Results
{
"result": <result>,
"id": <id>
}
| Item | Data type | Description |
| ----------- |:---------:| ----------------------- |
| result | any | request specific result |
| id | integer | id, same as request |
##### Error notifications
{
"error": {
"code": <code>
},
"id": <id>
}
| Item | Data type | Description |
| ----------- |:---------:| ------------------- |
| code | integer | error code |
| id | integer | id, same as request |
##### Error codes
| Symbolic name | Code | Description |
| ------------------ | ---------:| ---------------------- |
| GOOD | 0 | no error |
| BAD | 1 | generic error |
| BAD_NOTIMPLEMENTED | 2 | method not implemented |
| BAD_TIMEOUT | 3 | timeout occured |
| BAD_BUSY | 4 | resource busy |
| BAD_FORMAT | 5 | invalid formt |
| BAD_NOENTRY | 101 | invalid entry |
| BAD_ACCESS_DENIED | 102 | access not allowed |
#### Notification
Notfications are used to inform a receiver about something. Unlike requests, notifications are not answered. Therefore, an id is not supplied.
{
"method": <method_name>,
"params": <params>
}
| Item | Data type | Description |
| ----------- |:---------:| --------------------------------- |
| method_name | string | name of the method to invoke |
| params | array | method specific parameters |
### Requests (Adapter -> Provider)
#### lookup
Retrieve information about a filesystem entry by name.
webfuse daemon: {"method": "lookup", "params": [<filesystem>, <parent>, <name>], "id": <id>}
fs provider: {"result": {
"inode": <inode>,
"mode" : <mode>,
"type" : <type>,
"size" : <size>,
"atime": <atime>,
"mtime": <mtime>,
"ctime": <ctime>
}, "id": <id>}
| Item | Data type | Description |
| ----------- | --------------- | ------------------------------------------- |
| filesystem | string | name of the filesystem |
| parent | integer | inode of parent directory (1 = root) |
| name | string | name of the filesystem object to look up |
| inode | integer | inode of the filesystem object |
| mode | integer | unix file mode |
| type | "file" or "dir" | type of filesystem object |
| size | integer | required for files; file size in bytes |
| atime | integer | optional; unix time of last access |
| mtime | integer | optional; unix time of last modification |
| ctime | intefer | optional; unix time of last metadata change |
#### getattr
Get file attributes.
webfuse daemon: {"method": "getattr", "params": [<filesystem>, <inode>], "id": <id>}
fs provider: {"result": {
"mode" : <mode>,
"type" : <type>,
"size" : <size>,
"atime": <atime>,
"mtime": <mtime>,
"ctime": <ctime>
}, "id": <id>}
| Item | Data type | Description |
| ----------- | --------------- | ------------------------------------------- |
| filesystem | string | name of the filesystem |
| inode | integer | inode of the filesystem object |
| mode | integer | unix file mode |
| type | "file" or "dir" | type of filesystem object |
| size | integer | required for files; file size in bytes |
| atime | integer | optional; unix time of last access |
| mtime | integer | optional; unix time of last modification |
| ctime | intefer | optional; unix time of last metadata change |
#### readdir
Read directory contents.
Result is an array of name-inode pairs for each entry. The generic entries
"." and ".." should also be provided.
webfuse daemon: {"method": "readdir", "params": [<filesystem>, <dir_inode>], "id": <id>}
fs provider: {"result": [
{"name": <name>, "inode": <inode>},
...
], "id": <id>}
| Item | Data type | Description |
| ----------- | --------------- | ------------------------------ |
| filesystem | string | name of the filesystem |
| dir_inode | integer | inode of the directory to read |
| name | integer | name of the entry |
| inode | integer | inode of the entry |
#### open
Open a file.
webfuse daemon: {"method": "readdir", "params": [<filesystem>, <inode>, <flags>], "id": <id>}
fs provider: {"result": {"handle": <handle>}, "id": <id>}
| Item | Data type | Description |
| ----------- | ----------| ----------------------------- |
| filesystem | string | name of the filesystem |
| inode | integer | inode of the file |
| flags | integer | access mode flags (see below) |
| handle | integer | handle of the file |
##### Flags
| Symbolic name | Code | Description |
| --------------| ---------:| --------------------------- |
| O_ACCMODE | 0x003 | access mode mask |
| O_RDONLY | 0x000 | open for reading only |
| O_WRONLY | 0x001 | open for writing only |
| O_RDWR | 0x002 | open for reading an writing |
| O_CREAT | 0x040 | create (a new) file |
| O_EXCL | 0x080 | open file exclusivly |
| O_TRUNC | 0x200 | open file to truncate |
| O_APPEND | 0x400 | open file to append |
#### close
Informs filesystem provider, that a file is closed.
Since `close` is a notification, it cannot fail.
webfuse daemon: {"method": "close", "params": [<filesystem>, <inode>, <handle>, <flags>], "id": <id>}
| Item | Data type | Description |
| ----------- | ----------| ---------------------------- |
| filesystem | string | name of the filesystem |
| inode | integer | inode of the file |
| handle | integer | handle of the file |
| flags | integer | access mode flags (see open) |
#### read
Read from an open file.
webfuse daemon: {"method": "close", "params": [<filesystem>, <inode>, <handle>, <offset>, <length>], "id": <id>}
fs provider: {"result": {
"data": <data>,
"format": <format>,
"count": <count>
}, "id": <id>}
| Item | Data type | Description |
| ----------- | ----------| ----------------------------- |
| filesystem | string | name of the filesystem |
| inode | integer | inode of the file |
| handle | integer | handle of the file |
| offset | integer | Offet to start read operation |
| length | integer | Max. number of bytes to read |
| data | integer | handle of the file |
| format | string | Encoding of data (see below) |
| count | integer | Actual number of bytes read |
##### Format
| Format | Description |
| ---------- | -------------------------------------------------------- |
| "identiy" | Use data as is; note that JSON strings are UTF-8 encoded |
| "base64" | data is base64 encoded |
### Requests (Provider -> Adapter)
#### add_filesystem
Adds a filesystem.
fs provider: {"method": "add_filesytem", "params": [<name>], "id": <id>}
webfuse daemon: {"result": {"id": <name>}, "id": <id>}
| Item | Data type | Description |
| ----------- | ----------| ------------------------------- |
| name | string | name and id of filesystem |
#### authtenticate
Authenticate the provider.
If authentication is enabled, a provider must be authenticated by the adapter before filesystems can be added.
fs provider: {"method": "authenticate", "params": [<type>, <credentials>], "id": <id>}
webfuse daemon: {"result": {}, "id": <id>}
| Item | Data type | Description |
| ----------- | ----------| ------------------------------- |
| type | string | authentication type (see below) |
| credentials | object | credentials to authenticate |
##### authentication types
- **username**: authenticate via username and password
`{"username": <username>, "password": <password>}`
## Authentication
By default, webfuse daemon will redirect each filesystem call to the first connected provider without any authentication.
This might be good for testing purposes or when an external authentication mechanism is used. In some use cases, explicit authentication is needed. Therefore, authentication can be enabled within webfuse daemon.
When authentication is enabled, filesystem calls are only redirected to a connected provider, after `authenticate`
has succeeded.
![authenticate](doc/authenticate.png)
### Enable authentication
Authentication is enabled, if one or more authenticators are registered via `wf_server_config`.
static bool authenticate(struct wf_credentials * creds, void * user_data)
{
char const * username = wf_credentials_get(creds, "username");
char const * password = wf_credentials_get(creds, "password");
return ((NULL != username) && (0 == strcmp(username, "bob")) &&
(NULL != password) && (0 == strcmp(password, "???")));
}
wf_server_config * config = wf_server_config_create();
wf_server_config_add_authenticator(config, "username", &authenticate, NULL);
wf_server * server = wf_server_create(config);
//...
### Authenticator types and credentidals
Each authenticator is identified by a user defined string, called `type`. The type is provided by the `authenticate` request, so you can define different authenticators for different authentication types, e.g. username, certificate, token.
Actually, only one type is used: **username**
**It is strongly recommended to prefix custom authenticator types with an underscore (`_`) to avoid name clashes.**
The `wf_credentials`struct represents a map to access credentials as key-value pairs, where both, key and value, are of type string.
#### username
The authenticator type **username** is used to authenticate via username and password. Valid credentials should contain two keys.
- **username** refers to the name of the user
- **password** refers to the password of the user
**Note** that no further encryption is done, so this authenticator type should not be used over unencrypted websocket connections.
## Build and run
To install dependencies, see below.
cd webfuse
mkdir .build
cd .build
cmake ..
mkdir test
./webfused -m test --document_root=../exmaple/daemon/www --port=4711
### Build options
By default, unit tests and example application are enabled. You can disable them using the following cmake options:
- **WITHOUT_TESTS**: disable tests
`cmake -DWITHOUT_TESTS=ON ..`
- **WITHOUT_EXAMPLE**: disable example
`cmake -DWITHOUD_EXAMPLE=ON ..`
## Dependencies
- [libfuse3](https://github.com/libfuse/libfuse/)
- [libwebsockets](https://libwebsockets.org/)
- [Jansson](https://jansson.readthedocs.io)
- [GoogleTest](https://github.com/google/googletest) *(optional)*
### Installation from source
#### libfuse
wget -O fuse-3.1.1.tar.gz https://github.com/libfuse/libfuse/archive/fuse-3.1.1.tar.gz
tar -xf fuse-3.1.1.tar.gz
cd libfuse-fuse-3.1.1
./makeconf.sh
./configure
make
sudo make install
#### libwebsockets
wget -O libwebsockets-3.1.0.tar.gz https://github.com/warmcat/libwebsockets/archive/v3.1.0.tar.gz
tar -xf libwebsockets-3.1.0.tar.gz
cd libwebsockets-3.1.0
mkdir .build
cd .build
cmake ..
make
sudo make install
#### Jansson
wget -O libjansson-2.12.tar.gz https://github.com/akheron/jansson/archive/v2.12.tar.gz
tar -xf libjansson-2.12.tar.gz
cd jansson-2.12
mkdir .build
cd .build
cmake ..
make
sudo make install
#### GoogleTest
Installation of GoogleTest is optional webfuse library, but required to compile tests.
## Further Documentation
wget -O gtest-1.8.1.tar.gz https://github.com/google/googletest/archive/release-1.8.1.tar.gz
tar -xf gtest-1.8.1.tar.gz
cd googletest-release-1.8.1
mkdir .build
cd .build
cmake ..
make
sudo make install
- [Build instructions](doc/build.md)
- [Webfuse Protocol](doc/protocol.md)
- [API](doc/api.md)

@ -1 +1 @@
0.2.0
0.3.0

@ -1,20 +1,23 @@
ARG REGISTRY_PREFIX=''
ARG CODENAME=testing-slim
ARG CODENAME=3.9
FROM ${REGISTRY_PREFIX}debian:${CODENAME} as builder
FROM ${REGISTRY_PREFIX}alpine:${CODENAME} as builder
RUN set -x \
&& apt update \
&& apt upgrade -y \
&& apt install --yes --no-install-recommends \
build-essential \
&& apk add --no-cache \
bash \
coreutils \
gcc \
g++ \
make \
cmake \
ninja-build \
pkg-config \
ninja \
pkgconf \
rsync \
gdb \
gdbserver \
valgrind
valgrind
# util-linux \
# util-linux-dev
COPY src /usr/local/src
@ -23,8 +26,8 @@ ARG PARALLELMFLAGS=-j2
ARG DUMB_INIT_VERSION=1.2.2
RUN set -x \
&& builddeps="xxd" \
&& apt install --yes --no-install-recommends $builddeps \
&& builddeps="vim" \
&& apk add --no-cache --virtual .build-deps $builddeps \
&& builddir="/tmp/out" \
&& mkdir -p "$builddir" \
&& cd "$builddir" \
@ -35,9 +38,9 @@ RUN set -x \
&& mv dumb-init /usr/local/bin/dumb-init \
&& dumb-init --version \
&& rm -rf "$builddir" \
&& apt purge -y $builddeps
&& apk del .build-deps
ARG GTEST_VERSION=1.8.1
ARG GTEST_VERSION=1.10.0
RUN set -x \
&& builddir="/tmp/out" \
@ -47,34 +50,39 @@ RUN set -x \
&& make "$PARALLELMFLAGS" install \
&& rm -rf "$builddir"
ARG FUSE_VERSION=3.1.1
ARG FUSE_VERSION=3.9.1
RUN set -x \
&& builddeps="libtool automake gettext" \
&& apt install --yes --no-install-recommends $builddeps \
&& cd "/usr/local/src/libfuse-fuse-$FUSE_VERSION" \
&& ./makeconf.sh \
&& builddeps="linux-headers eudev-dev python3 py3-pip py3-setuptools py3-cryptography" \
&& apk add --no-cache --virtual .build-deps $builddeps \
&& pip3 install meson \
&& builddir="/tmp/out" \
&& mkdir -p "$builddir" \
&& cd "$builddir" \
&& "/usr/local/src/libfuse-fuse-$FUSE_VERSION/configure" \
&& make "$PARALLELMFLAGS" install \
&& meson "/usr/local/src/libfuse-fuse-$FUSE_VERSION" \
&& meson configure -Dexamples=false \
&& ninja \
&& ninja install \
&& pip3 uninstall -y meson \
&& rm -rf "$builddir" \
&& apt purge -y $builddeps
&& apk del .build-deps
ARG WEBSOCKETS_VERSION=3.1.0
ARG WEBSOCKETS_VERSION=4.0.10
RUN set -x \
&& apt install --yes --no-install-recommends \
&& builddeps="linux-headers" \
&& apk add --no-cache --virtual .build-deps $builddeps \
&& apk add --no-cache \
ca-certificates \
openssl \
libssl-dev \
openssl-dev \
&& builddir="/tmp/out" \
&& mkdir -p "$builddir" \
&& cd "$builddir" \
&& cmake "/usr/local/src/libwebsockets-$WEBSOCKETS_VERSION" \
&& make "$PARALLELMFLAGS" install \
&& rm -rf "$builddir"
&& rm -rf "$builddir" \
&& apk del .build-deps
ARG JANSSON_VERSION=2.12
@ -87,6 +95,7 @@ RUN set -x \
&& rm -rf "$builddir"
ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
ENV PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig
ARG USERID=1000
@ -95,14 +104,10 @@ ARG OUTDIR=/workspace/out
ARG SCRIPTDIR=/workspace/bin
RUN set -x \
&& useradd -u "$USERID" -ms /bin/bash user \
&& adduser -u "$USERID" -s /bin/bash -D user \
&& mkdir -p "$PROJECTDIR" "$OUTDIR" "$SCRIPTDIR" \
&& chown user:user "$PROJECTDIR" "$OUTDIR" "$SCRIPTDIR"
WORKDIR "$OUTDIR"
ENTRYPOINT ["dumb-init", "--"]
# unused
ARG QEMU_VERSION_=v3.1.0-2

@ -15,8 +15,7 @@ RUN set -x \
gdb \
gdbserver \
valgrind \
lcov \
uuid-dev
lcov
COPY src /usr/local/src
@ -39,7 +38,7 @@ RUN set -x \
&& rm -rf "$builddir" \
&& apt purge -y $builddeps
ARG GTEST_VERSION=1.8.1
ARG GTEST_VERSION=1.10.0
RUN set -x \
&& builddir="/tmp/out" \
@ -49,22 +48,24 @@ RUN set -x \
&& make "$PARALLELMFLAGS" install \
&& rm -rf "$builddir"
ARG FUSE_VERSION=3.1.1
ARG FUSE_VERSION=3.9.1
RUN set -x \
&& builddeps="libtool automake gettext" \
&& builddeps="udev gettext python3 python3-pip python3-setuptools python3-wheel" \
&& apt install --yes --no-install-recommends $builddeps \
&& cd "/usr/local/src/libfuse-fuse-$FUSE_VERSION" \
&& ./makeconf.sh \
&& pip3 install --system meson \
&& builddir="/tmp/out" \
&& mkdir -p "$builddir" \
&& cd "$builddir" \
&& "/usr/local/src/libfuse-fuse-$FUSE_VERSION/configure" \
&& make "$PARALLELMFLAGS" install \
&& meson "/usr/local/src/libfuse-fuse-$FUSE_VERSION" \
&& meson configure -Dexamples=false \
&& ninja \
&& ninja install \
&& pip3 uninstall -y meson \
&& rm -rf "$builddir" \
&& apt purge -y $builddeps
ARG WEBSOCKETS_VERSION=3.1.0
ARG WEBSOCKETS_VERSION=4.0.10
RUN set -x \
&& apt install --yes --no-install-recommends \
@ -104,7 +105,3 @@ RUN set -x \
WORKDIR "$OUTDIR"
ENTRYPOINT ["dumb-init", "--"]
# unused
ARG QEMU_VERSION_=v3.1.0-2

@ -1,23 +1,27 @@
ARG REGISTRY_PREFIX=''
ARG CODENAME=testing-slim
ARG CODENAME=3.9
FROM ${REGISTRY_PREFIX}arm32v7/debian:${CODENAME} as builder
FROM ${REGISTRY_PREFIX}arm32v7/alpine:${CODENAME} as builder
ARG QEMU_VERSION_=v3.1.0-2
ARG QEMU_VERSION_=v4.1.0-1
COPY docker/qemu-arm-static-$QEMU_VERSION_ /usr/bin/qemu-arm-static
RUN set -x \
&& apt update \
&& apt upgrade -y \
&& apt install --yes --no-install-recommends \
build-essential \
&& apk add --no-cache \
bash \
coreutils \
gcc \
g++ \
make \
cmake \
ninja-build \
pkg-config \
ninja \
pkgconf \
rsync \
gdb \
gdbserver
valgrind
# util-linux \
# util-linux-dev
COPY src /usr/local/src
@ -26,8 +30,8 @@ ARG PARALLELMFLAGS=-j2
ARG DUMB_INIT_VERSION=1.2.2
RUN set -x \
&& builddeps="xxd" \
&& apt install --yes --no-install-recommends $builddeps \
&& builddeps="vim" \
&& apk add --no-cache --virtual .build-deps $builddeps \
&& builddir="/tmp/out" \
&& mkdir -p "$builddir" \
&& cd "$builddir" \
@ -38,9 +42,9 @@ RUN set -x \
&& mv dumb-init /usr/local/bin/dumb-init \
&& dumb-init --version \
&& rm -rf "$builddir" \
&& apt purge -y $builddeps
&& apk del .build-deps
ARG GTEST_VERSION=1.8.1
ARG GTEST_VERSION=1.10.0
RUN set -x \
&& builddir="/tmp/out" \
@ -50,34 +54,39 @@ RUN set -x \
&& make "$PARALLELMFLAGS" install \
&& rm -rf "$builddir"
ARG FUSE_VERSION=3.1.1
ARG FUSE_VERSION=3.9.1
RUN set -x \
&& builddeps="libtool automake gettext" \
&& apt install --yes --no-install-recommends $builddeps \
&& cd "/usr/local/src/libfuse-fuse-$FUSE_VERSION" \
&& ./makeconf.sh \
&& builddeps="linux-headers eudev-dev python3 py3-pip py3-setuptools py3-cryptography" \
&& apk add --no-cache --virtual .build-deps $builddeps \
&& pip3 install meson \
&& builddir="/tmp/out" \
&& mkdir -p "$builddir" \
&& cd "$builddir" \
&& "/usr/local/src/libfuse-fuse-$FUSE_VERSION/configure" \
&& make "$PARALLELMFLAGS" install \
&& meson "/usr/local/src/libfuse-fuse-$FUSE_VERSION" \
&& meson configure -Dexamples=false \
&& ninja \
&& ninja install \
&& pip3 uninstall -y meson \
&& rm -rf "$builddir" \
&& apt purge -y $builddeps
&& apk del .build-deps
ARG WEBSOCKETS_VERSION=3.1.0
ARG WEBSOCKETS_VERSION=4.0.10
RUN set -x \
&& apt install --yes --no-install-recommends \
&& builddeps="linux-headers" \
&& apk add --no-cache --virtual .build-deps $builddeps \
&& apk add --no-cache \
ca-certificates \
openssl \
libssl-dev \
openssl-dev \
&& builddir="/tmp/out" \
&& mkdir -p "$builddir" \
&& cd "$builddir" \
&& cmake "/usr/local/src/libwebsockets-$WEBSOCKETS_VERSION" \
&& make "$PARALLELMFLAGS" install \
&& rm -rf "$builddir"
&& rm -rf "$builddir" \
&& apk del .build-deps
ARG JANSSON_VERSION=2.12
@ -90,6 +99,7 @@ RUN set -x \
&& rm -rf "$builddir"
ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
ENV PKG_CONFIG_PATH=/usr/local/lib32/pkgconfig
ARG USERID=1000
@ -98,7 +108,7 @@ ARG OUTDIR=/workspace/out
ARG SCRIPTDIR=/workspace/bin
RUN set -x \
&& useradd -u "$USERID" -ms /bin/bash user \
&& adduser -u "$USERID" -s /bin/bash -D user \
&& mkdir -p "$PROJECTDIR" "$OUTDIR" "$SCRIPTDIR" \
&& chown user:user "$PROJECTDIR" "$OUTDIR" "$SCRIPTDIR"

@ -3,7 +3,7 @@ ARG CODENAME=bionic
FROM ${REGISTRY_PREFIX}arm32v7/ubuntu:${CODENAME} as builder
ARG QEMU_VERSION_=v3.1.0-2
ARG QEMU_VERSION_=v4.1.0-1
COPY docker/qemu-arm-static-$QEMU_VERSION_ /usr/bin/qemu-arm-static
@ -18,8 +18,7 @@ RUN set -x \
rsync \
gdb \
gdbserver \
lcov \
uuid-dev
lcov
COPY src /usr/local/src
@ -42,7 +41,7 @@ RUN set -x \
&& rm -rf "$builddir" \
&& apt purge -y $builddeps
ARG GTEST_VERSION=1.8.1
ARG GTEST_VERSION=1.10.0
RUN set -x \
&& builddir="/tmp/out" \
@ -52,22 +51,24 @@ RUN set -x \
&& make "$PARALLELMFLAGS" install \
&& rm -rf "$builddir"
ARG FUSE_VERSION=3.1.1
ARG FUSE_VERSION=3.9.1
RUN set -x \
&& builddeps="libtool automake gettext" \
&& builddeps="udev gettext python3 python3-pip python3-setuptools python3-wheel" \
&& apt install --yes --no-install-recommends $builddeps \
&& cd "/usr/local/src/libfuse-fuse-$FUSE_VERSION" \
&& ./makeconf.sh \
&& pip3 install --system meson \
&& builddir="/tmp/out" \
&& mkdir -p "$builddir" \
&& cd "$builddir" \
&& "/usr/local/src/libfuse-fuse-$FUSE_VERSION/configure" \
&& make "$PARALLELMFLAGS" install \
&& meson "/usr/local/src/libfuse-fuse-$FUSE_VERSION" \
&& meson configure -Dexamples=false \
&& ninja \
&& ninja install \
&& pip3 uninstall -y meson \
&& rm -rf "$builddir" \
&& apt purge -y $builddeps
ARG WEBSOCKETS_VERSION=3.1.0
ARG WEBSOCKETS_VERSION=4.0.10
RUN set -x \
&& apt install --yes --no-install-recommends \

@ -0,0 +1,30 @@
set(CMAKE_C_FLAGS_COVERAGE
"${CMAKE_C_FLAGS_DEBUG} -pg --coverage -fprofile-arcs -ftest-coverage"
CACHE STRING "Flags used by the C compiler during coverage builds"
FORCE
)
set(CMAKE_CXX_FLAGS_COVERAGE
"${CMAKE_CXX_FLAGS_DEBUG} -pg --coverage -fprofile-arcs -ftest-coverage"
CACHE STRING "Flags used by the C++ compiler during coverage builds."
FORCE
)
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used for linking binaries during coverage builds."
FORCE
)
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
FORCE
)
mark_as_advanced(
CMAKE_C_FLAGS_COVERAGE
CMAKE_CXX_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE
)

@ -0,0 +1,136 @@
if(NOT WITHOUT_TESTS AND NOT WITHOUT_ADAPTER AND NOT WITHOUT_PROVIDER)
set(MEMORYCHECK_COMMAND_OPTIONS "--leak-check=full --error-exitcode=1")
include (CTest)
add_executable(fs_check
test/webfuse/tests/integration/fs_check.c
)
pkg_check_modules(GTEST gtest_main)
include(GoogleTest)
pkg_check_modules(GMOCK gmock)
add_executable(alltests
test/webfuse/tests/core/jsonrpc/mock_timer_callback.cc
test/webfuse/tests/core/jsonrpc/mock_timer.cc
test/webfuse/tests/core/jsonrpc/test_is_request.cc
test/webfuse/tests/core/jsonrpc/test_request.cc
test/webfuse/tests/core/jsonrpc/test_is_response.cc
test/webfuse/tests/core/jsonrpc/test_response.cc
test/webfuse/tests/core/jsonrpc/test_server.cc
test/webfuse/tests/core/jsonrpc/test_proxy.cc
test/webfuse/tests/core/jsonrpc/test_response_parser.cc
test/webfuse/tests/core/timer/test_timepoint.cc
test/webfuse/tests/core/timer/test_timer.cc
test/webfuse/utils/tempdir.cc
test/webfuse/utils/file_utils.cc
test/webfuse/utils/timeout_watcher.cc
test/webfuse/utils/path.c
test/webfuse/utils/static_filesystem.c
test/webfuse/utils/ws_server.cc
test/webfuse/mocks/fake_invokation_context.cc
test/webfuse/mocks/mock_authenticator.cc
test/webfuse/mocks/mock_request.cc
test/webfuse/mocks/mock_provider_client.cc
test/webfuse/mocks/mock_provider.cc
test/webfuse/mocks/mock_fuse.cc
test/webfuse/mocks/mock_operation_context.cc
test/webfuse/mocks/mock_jsonrpc_proxy.cc
test/webfuse//tests/core/test_util.cc
test/webfuse/tests/core/test_container_of.cc
test/webfuse/tests/core/test_string.cc
test/webfuse/tests/core/test_slist.cc
test/webfuse/tests/core/test_base64.cc
test/webfuse/tests/core/test_status.cc
test/webfuse/tests/core/test_message.cc
test/webfuse/tests/core/test_message_queue.cc
test/webfuse/tests/adapter/test_server.cc
test/webfuse/tests/adapter/test_server_config.cc
test/webfuse/tests/adapter/test_credentials.cc
test/webfuse/tests/adapter/test_authenticator.cc
test/webfuse/tests/adapter/test_authenticators.cc
test/webfuse/tests/adapter/test_mountpoint.cc
test/webfuse/tests/adapter/test_fuse_req.cc
test/webfuse/tests/adapter/operation/test_context.cc
test/webfuse/tests/adapter/operation/test_open.cc
test/webfuse/tests/adapter/operation/test_close.cc
test/webfuse/tests/adapter/operation/test_read.cc
test/webfuse/tests/adapter/operation/test_readdir.cc
test/webfuse/tests/adapter/operation/test_getattr.cc
test/webfuse/tests/adapter/operation/test_lookup.cc
test/webfuse/tests/provider/test_url.cc
test/webfuse/tests/provider/test_client_protocol.cc
test/webfuse/tests/provider/operation/test_close.cc
test/webfuse/tests/provider/operation/test_getattr.cc
test/webfuse/tests/provider/operation/test_lookup.cc
test/webfuse/tests/provider/operation/test_open.cc
test/webfuse/tests/provider/operation/test_read.cc
test/webfuse/tests/provider/operation/test_readdir.cc
test/webfuse/tests/integration/test_lowlevel.cc
test/webfuse/tests/integration/test_integration.cc
test/webfuse/tests/integration/file.cc
test/webfuse/tests/integration/server.cc
test/webfuse/tests/integration/provider.cc
)
target_link_libraries(alltests PUBLIC
-Wl,--wrap=wf_timer_manager_create
-Wl,--wrap=wf_timer_manager_dispose
-Wl,--wrap=wf_timer_manager_check
-Wl,--wrap=wf_timer_create
-Wl,--wrap=wf_timer_dispose
-Wl,--wrap=wf_timer_start
-Wl,--wrap=wf_timer_cancel
-Wl,--wrap=wf_impl_operation_context_get_proxy
-Wl,--wrap=wf_jsonrpc_proxy_vinvoke
-Wl,--wrap=wf_jsonrpc_proxy_vnotify
-Wl,--wrap=fuse_req_userdata
-Wl,--wrap=fuse_reply_open
-Wl,--wrap=fuse_reply_err
-Wl,--wrap=fuse_reply_buf
-Wl,--wrap=fuse_reply_attr
-Wl,--wrap=fuse_reply_entry
-Wl,--wrap=fuse_req_ctx
webfuse-adapter-static
webfuse-provider-static
webfuse-core
${FUSE3_LIBRARIES}
${LWS_LIBRARIES}
${JANSSON_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${GMOCK_LIBRARIES}
${GTEST_LIBRARIES}
)
target_include_directories(alltests PUBLIC test lib ${FUSE3_INCLUDE_DIRS} ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS})
target_compile_options(alltests PUBLIC ${FUSE3_CFLAGS_OTHER} ${GMOCK_CFLAGS} ${GTEST_CFLAGS})
add_custom_command(OUTPUT server-key.pem
COMMAND openssl req -x509 -newkey rsa:4096 -keyout server-key.pem -out server-cert.pem -days 365 -nodes -batch -subj '/CN=localhost'
COMMAND openssl req -x509 -newkey rsa:4096 -keyout client-key.pem -out client-cert.pem -days 365 -nodes -batch -subj '/CN=localhost'
)
add_custom_target(gen-tls DEPENDS server-key.pem)
add_dependencies(alltests gen-tls)
enable_testing()
gtest_discover_tests(alltests TEST_PREFIX alltests:)
add_custom_target(coverage
mkdir -p coverage
COMMAND lcov --initial --capture --directory . --output-file coverage/lcov_base.info --rc lcov_branch_coverage=1
COMMAND ./alltests
COMMAND lcov --capture --directory . --output-file coverage/lcov.info --rc lcov_branch_coverage=1
COMMAND lcov --remove coverage/lcov.info '/usr/*' --output-file coverage/lcov.info --rc lcov_branch_coverage=1
COMMAND lcov --remove coverage/lcov.info '*/test/*' --output-file coverage/lcov.info --rc lcov_branch_coverage=1
)
add_dependencies(coverage alltests)
add_custom_target(coverage-report
COMMAND genhtml --branch-coverage --highlight --legend coverage/lcov.info --output-directory coverage/report
)
add_dependencies(coverage-report coverage)
endif(NOT WITHOUT_TESTS AND NOT WITHOUT_ADAPTER AND NOT WITHOUT_PROVIDER)

@ -0,0 +1,79 @@
if(NOT WITHOUT_ADAPTER)
pkg_check_modules(FUSE3 REQUIRED fuse3)
add_library(webfuse-adapter-static STATIC
lib/webfuse/adapter/api.c
lib/webfuse/adapter/impl/filesystem.c
lib/webfuse/adapter/impl/server.c
lib/webfuse/adapter/impl/server_config.c
lib/webfuse/adapter/impl/server_protocol.c
lib/webfuse/adapter/impl/session.c
lib/webfuse/adapter/impl/session_manager.c
lib/webfuse/adapter/impl/authenticator.c
lib/webfuse/adapter/impl/authenticators.c
lib/webfuse/adapter/impl/credentials.c
lib/webfuse/adapter/impl/mountpoint.c
lib/webfuse/adapter/impl/mountpoint_factory.c
lib/webfuse/adapter/impl/operation/context.c
lib/webfuse/adapter/impl/operation/lookup.c
lib/webfuse/adapter/impl/operation/getattr.c
lib/webfuse/adapter/impl/operation/readdir.c
lib/webfuse/adapter/impl/operation/open.c
lib/webfuse/adapter/impl/operation/close.c
lib/webfuse/adapter/impl/operation/read.c
)
target_include_directories(webfuse-adapter-static PRIVATE
lib
${FUSE3_INCLUDE_DIRS}
)
target_compile_options(webfuse-adapter-static PUBLIC
${FUSE3_CFLAGS_OTHER}
)
set_target_properties(webfuse-adapter-static PROPERTIES OUTPUT_NAME webfuse-adapter)
set_target_properties(webfuse-adapter-static PROPERTIES C_VISIBILITY_PRESET hidden)
add_library(webfuse-adapter SHARED
lib/webfuse/adapter/api.c
)
target_include_directories(webfuse-adapter PRIVATE
${FUSE3_INCLUDE_DIRS}
)
target_compile_options(webfuse-adapter PUBLIC
${FUSE3_CFLAGS_OTHER}
)
set_target_properties(webfuse-adapter PROPERTIES VERSION ${PROJECT_VERSION})
set_target_properties(webfuse-adapter PROPERTIES SOVERSION 0)
set_target_properties(webfuse-adapter PROPERTIES C_VISIBILITY_PRESET hidden)
set_target_properties(webfuse-adapter PROPERTIES COMPILE_DEFINITIONS "WF_API=WF_EXPORT")
target_link_libraries(webfuse-adapter PRIVATE webfuse-adapter-static webfuse-core)
file(WRITE "${PROJECT_BINARY_DIR}/libwebfuse-adapter.pc"
"prefix=\"${CMAKE_INSTALL_PREFIX}\"
exec_prefix=\${prefix}
libdir=\${exec_prefix}/lib${LIB_SUFFIX}
includedir=\${prefix}/include
Name: libwebfuse
Description: Websockets filesystem server library
Version: ${PROJECT_VERSION}
Libs: -L\${libdir} -lwebfuse-adapter -l${FUSE3_LIBRARIES} -l${LWS_LIBRARIES} -l${JANSSON_LIBRARIES}
Cflags: -I\${includedir}"
)
install(TARGETS webfuse-adapter DESTINATION lib${LIB_SUFFIX} COMPONENT libraries)
install(FILES "${PROJECT_BINARY_DIR}/libwebfuse-adapter.pc" DESTINATION lib${LIB_SUFFIX}/pkgconfig COMPONENT libraries)
install(FILES include/webfuse_adapter.h DESTINATION include COMPONENT headers)
install(DIRECTORY include/webfuse/adapter DESTINATION include/webfuse COMPONENT headers)
endif(NOT WITHOUT_ADAPTER)

@ -0,0 +1,29 @@
# libwebfuse-core
add_library(webfuse-core STATIC
lib/webfuse/core/slist.c
lib/webfuse/core/message.c
lib/webfuse/core/message_queue.c
lib/webfuse/core/status.c
lib/webfuse/core/string.c
lib/webfuse/core/base64.c
lib/webfuse/core/lws_log.c
lib/webfuse/core/json_util.c
lib/webfuse/core/timer/manager.c
lib/webfuse/core/timer/timepoint.c
lib/webfuse/core/timer/timer.c
lib/webfuse/core/jsonrpc/proxy.c
lib/webfuse/core/jsonrpc/proxy_variadic.c
lib/webfuse/core/jsonrpc/server.c
lib/webfuse/core/jsonrpc/method.c
lib/webfuse/core/jsonrpc/request.c
lib/webfuse/core/jsonrpc/response.c
lib/webfuse/core/jsonrpc/error.c
)
set_target_properties(webfuse-core PROPERTIES OUTPUT_NAME webfuse-core)
target_include_directories(webfuse-core PUBLIC lib lib/wf/jsonrpc/include)
set_target_properties(webfuse-core PROPERTIES C_VISIBILITY_PRESET hidden)
install(DIRECTORY include/webfuse/core DESTINATION include/webfuse COMPONENT headers)

@ -0,0 +1,58 @@
if(NOT WITHOUT_PROVIDER)
add_library(webfuse-provider-static STATIC
lib/webfuse/provider/api.c
lib/webfuse/provider/impl/url.c
lib/webfuse/provider/impl/client.c
lib/webfuse/provider/impl/client_config.c
lib/webfuse/provider/impl/client_protocol.c
lib/webfuse/provider/impl/provider.c
lib/webfuse/provider/impl/request.c
lib/webfuse/provider/impl/dirbuffer.c
lib/webfuse/provider/impl/credentials.c
lib/webfuse/provider/impl/operation/lookup.c
lib/webfuse/provider/impl/operation/getattr.c
lib/webfuse/provider/impl/operation/readdir.c
lib/webfuse/provider/impl/operation/open.c
lib/webfuse/provider/impl/operation/close.c
lib/webfuse/provider/impl/operation/read.c
)
set_target_properties(webfuse-provider-static PROPERTIES OUTPUT_NAME webfuse-provider)
set_target_properties(webfuse-provider-static PROPERTIES C_VISIBILITY_PRESET hidden)
target_include_directories(webfuse-provider-static PRIVATE
lib
)
add_library(webfuse-provider SHARED
lib/webfuse/provider/api.c
)
set_target_properties(webfuse-provider PROPERTIES VERSION ${PROJECT_VERSION})
set_target_properties(webfuse-provider PROPERTIES SOVERSION 0)
set_target_properties(webfuse-provider PROPERTIES C_VISIBILITY_PRESET hidden)
set_target_properties(webfuse-provider PROPERTIES COMPILE_DEFINITIONS "WFP_API=WFP_EXPORT")
target_include_directories(webfuse-provider PUBLIC lib)
target_link_libraries(webfuse-provider PRIVATE webfuse-provider-static webfuse-core)
file(WRITE "${PROJECT_BINARY_DIR}/libwebfuse-provider.pc"
"prefix=\"${CMAKE_INSTALL_PREFIX}\"
exec_prefix=\${prefix}
libdir=\${exec_prefix}/lib${LIB_SUFFIX}
includedir=\${prefix}/include
Name: libwebfuse-provider
Description: Provider library for websockets filesystem
Version: ${PROJECT_VERSION}
Libs: -L\${libdir} -lwebfuse-provider -l${LWS_LIBRARIES} -l${JANSSON_LIBRARIES}
Cflags: -I\${includedir}"
)
install(TARGETS webfuse-provider DESTINATION lib${LIB_SUFFIX} COMPONENT libraries)
install(FILES "${PROJECT_BINARY_DIR}/libwebfuse-provider.pc" DESTINATION lib${LIB_SUFFIX}/pkgconfig COMPONENT libraries)
install(FILES include/webfuse_provider.h DESTINATION include COMPONENT headers)
install(DIRECTORY include/webfuse/provider DESTINATION include/webfuse COMPONENT headers)
endif(NOT WITHOUT_PROVIDER)

@ -0,0 +1,12 @@
ignore:
- test
- lib/wf/timer/test
- lib/wf/jsonrpc/test
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: yes
macro: yes

@ -0,0 +1,55 @@
# Webfuse API introduction
This introduction provides a general overview to webfuse API.
Please refer to the [build instructions](build.md) to generate API reference documentation.
## Contents
- [Authentication](#Authentication)
## Authentication
By default, webfuse daemon will redirect each filesystem call to the first connected provider without any authentication.
This might be good for testing purposes or when an external authentication mechanism is used. In some use cases, explicit authentication is needed. Therefore, authentication can be enabled within webfuse daemon.
When authentication is enabled, filesystem calls are only redirected to a connected provider, after `authenticate`
has succeeded.
![authenticate](authenticate.png)
### Enable authentication
Authentication is enabled, if one or more authenticators are registered via `wf_server_config`.
static bool authenticate(struct wf_credentials * creds, void * user_data)
{
char const * username = wf_credentials_get(creds, "username");
char const * password = wf_credentials_get(creds, "password");
return ((NULL != username) && (0 == strcmp(username, "bob")) &&
(NULL != password) && (0 == strcmp(password, "???")));
}
wf_server_config * config = wf_server_config_create();
wf_server_config_add_authenticator(config, "username", &authenticate, NULL);
wf_server * server = wf_server_create(config);
//...
### Authenticator types and credentidals
Each authenticator is identified by a user defined string, called `type`. The type is provided by the `authenticate` request, so you can define different authenticators for different authentication types, e.g. username, certificate, token.
Actually, only one type is used: **username**
**It is strongly recommended to prefix custom authenticator types with an underscore (`_`) to avoid name clashes.**
The `wf_credentials`struct represents a map to access credentials as key-value pairs, where both, key and value, are of type string.
#### username
The authenticator type **username** is used to authenticate via username and password. Valid credentials should contain two keys.
- **username** refers to the name of the user
- **password** refers to the password of the user
**Note** that no further encryption is done, so this authenticator type should not be used over unencrypted websocket connections.

@ -0,0 +1,102 @@
# Build Instructions
To install dependencies, see below.
cd webfuse
mkdir .build
cd .build
cmake ..
make
## Build options
By default, unit tests are enabled. You can disable them using the following cmake options:
- **WITHOUT_TESTS**: disable tests
`cmake -DWITHOUT_TESTS=ON ..`
Since webfuse consists of two libraries, it is possible to disable one of them
in order to reduce build dependencies.
*Note that unit tests are only available, when both libraries are built.*
- **WITHOUT_ADAPTER**: omit adapter library
`cmake -DWITHOUT_ADAPTER=ON`
- **WIHTOU_PROVIDER**: omit provider library
`cmake -DWITHOUT_PROVIDER=ON`
## Build using Meson (experimental)
_Note: Meson build support is experimental. Do not rely on it._
meson .build
cd .build
ninja build
_Note: Build options are not supported yet._
## Create API documentation
To create API documentation, you must install doxygen and dot first.
After that, run doxygen in the project root directory.
doxygen
After that, you will find the API documentation in the doc/api subdirectory.
## Dependencies
- [libfuse3](https://github.com/libfuse/libfuse/)
- [libwebsockets](https://libwebsockets.org/)
- [Jansson](https://jansson.readthedocs.io)
- [GoogleTest](https://github.com/google/googletest) *(optional)*
### Installation from source
#### libfuse
To install libfuse, meson is needed. Please refer to [meson quick guide](https://mesonbuild.com/Quick-guide.html) for setup instructions.
wget -O fuse-3.9.1.tar.gz https://github.com/libfuse/libfuse/archive/fuse-3.9.1.tar.gz
tar -xf fuse-3.9.1.tar.gz
cd libfuse-fuse-3.9.1
mkdir .build
cd .build
meson ..
ninja
sudo ninja install
#### libwebsockets
wget -O libwebsockets-4.0.10.tar.gz https://github.com/warmcat/libwebsockets/archive/v4.0.10.tar.gz
tar -xf libwebsockets-4.0.10.tar.gz
cd libwebsockets-4.0.10
mkdir .build
cd .build
cmake ..
make
sudo make install
#### Jansson
wget -O libjansson-2.12.tar.gz https://github.com/akheron/jansson/archive/v2.12.tar.gz
tar -xf libjansson-2.12.tar.gz
cd jansson-2.12
mkdir .build
cd .build
cmake ..
make
sudo make install
#### GoogleTest
Installation of GoogleTest is optional webfuse library, but required to compile tests.
wget -O gtest-1.10.0.tar.gz https://github.com/google/googletest/archive/release-1.10.0.tar.gz
tar -xf gtest-1.10.0.tar.gz
cd googletest-release-1.10.0
mkdir .build
cd .build
cmake ..
make
sudo make install

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

@ -1,16 +0,0 @@
@startuml
salt
{
{T
+ mount_point
++ fwupdate
+++ default -> 7c029f81-6bdf-4d3c-82dc-26f748164012
+++ 7c029f81-6bdf-4d3c-82dc-26f748164012
++++ update.raucb
+++ f93de23b-4535-4a47-a287-a381b78a11b8
++++ update.raucb
}
}
@enduml

@ -0,0 +1,253 @@
# Webfuse Protocol
## Requests, responses and notifications
There are three types of messages, used for communication between webfuse daemon and filesystem provider. All message types are encoded in [JSON](https://www.json.org/) and strongly inspired by [JSON-RPC](https://www.jsonrpc.org/).
### Request
A request is used by a sender to invoke a method on the receiver. The sender awaits a response from the receiver. Since requests and responses can be sendet or answered in any order, an id is provided in each request to identify it.
{
"method": <method_name>,
"params": <params>,
"id" : <id>
}
| Item | Data type | Description |
| ----------- |:---------:| --------------------------------- |
| method_name | string | name of the method to invoke |
| params | array | method specific parameters |
| id | integer | id, which is repeated in response |
### Response
A response is used to answer a prior request. There are two kinds of responses:
#### Successful Results
{
"result": <result>,
"id": <id>
}
| Item | Data type | Description |
| ----------- |:---------:| ----------------------- |
| result | any | request specific result |
| id | integer | id, same as request |
#### Error notifications
{
"error": {
"code": <code>
},
"id": <id>
}
| Item | Data type | Description |
| ----------- |:---------:| ------------------- |
| code | integer | error code |
| id | integer | id, same as request |
#### Error codes
| Symbolic name | Code | Description |
| ------------------ | ---------:| ---------------------- |
| GOOD | 0 | no error |
| BAD | 1 | generic error |
| BAD_NOTIMPLEMENTED | 2 | method not implemented |
| BAD_TIMEOUT | 3 | timeout occured |
| BAD_BUSY | 4 | resource busy |
| BAD_FORMAT | 5 | invalid formt |
| BAD_NOENTRY | 101 | invalid entry |
| BAD_ACCESS_DENIED | 102 | access not allowed |
### Notification
Notfications are used to inform a receiver about something. Unlike requests, notifications are not answered. Therefore, an id is not supplied.
{
"method": <method_name>,
"params": <params>
}
| Item | Data type | Description |
| ----------- |:---------:| --------------------------------- |
| method_name | string | name of the method to invoke |
| params | array | method specific parameters |
## Requests (Adapter -> Provider)
### lookup
Retrieve information about a filesystem entry by name.
webfuse daemon: {"method": "lookup", "params": [<filesystem>, <parent>, <name>], "id": <id>}
fs provider: {"result": {
"inode": <inode>,
"mode" : <mode>,
"type" : <type>,
"size" : <size>,
"atime": <atime>,
"mtime": <mtime>,
"ctime": <ctime>
}, "id": <id>}
| Item | Data type | Description |
| ----------- | --------------- | ------------------------------------------- |
| filesystem | string | name of the filesystem |
| parent | integer | inode of parent directory (1 = root) |
| name | string | name of the filesystem object to look up |
| inode | integer | inode of the filesystem object |
| mode | integer | unix file mode |
| type | "file" or "dir" | type of filesystem object |
| size | integer | required for files; file size in bytes |
| atime | integer | optional; unix time of last access |
| mtime | integer | optional; unix time of last modification |
| ctime | intefer | optional; unix time of last metadata change |
### getattr
Get file attributes.
webfuse daemon: {"method": "getattr", "params": [<filesystem>, <inode>], "id": <id>}
fs provider: {"result": {
"mode" : <mode>,
"type" : <type>,
"size" : <size>,
"atime": <atime>,
"mtime": <mtime>,
"ctime": <ctime>
}, "id": <id>}
| Item | Data type | Description |
| ----------- | --------------- | ------------------------------------------- |
| filesystem | string | name of the filesystem |
| inode | integer | inode of the filesystem object |
| mode | integer | unix file mode |
| type | "file" or "dir" | type of filesystem object |
| size | integer | required for files; file size in bytes |
| atime | integer | optional; unix time of last access |
| mtime | integer | optional; unix time of last modification |
| ctime | intefer | optional; unix time of last metadata change |
### readdir
Read directory contents.
Result is an array of name-inode pairs for each entry. The generic entries
"." and ".." should also be provided.
webfuse daemon: {"method": "readdir", "params": [<filesystem>, <dir_inode>], "id": <id>}
fs provider: {"result": [
{"name": <name>, "inode": <inode>},
...
], "id": <id>}
| Item | Data type | Description |
| ----------- | --------------- | ------------------------------ |
| filesystem | string | name of the filesystem |
| dir_inode | integer | inode of the directory to read |
| name | integer | name of the entry |
| inode | integer | inode of the entry |
### open
Open a file.
webfuse daemon: {"method": "readdir", "params": [<filesystem>, <inode>, <flags>], "id": <id>}
fs provider: {"result": {"handle": <handle>}, "id": <id>}
| Item | Data type | Description |
| ----------- | ----------| ----------------------------- |
| filesystem | string | name of the filesystem |
| inode | integer | inode of the file |
| flags | integer | access mode flags (see below) |
| handle | integer | handle of the file |
#### Flags
| Symbolic name | Code | Description |
| --------------| ---------:| --------------------------- |
| O_ACCMODE | 0x003 | access mode mask |
| O_RDONLY | 0x000 | open for reading only |
| O_WRONLY | 0x001 | open for writing only |
| O_RDWR | 0x002 | open for reading an writing |
| O_CREAT | 0x040 | create (a new) file |
| O_EXCL | 0x080 | open file exclusivly |
| O_TRUNC | 0x200 | open file to truncate |
| O_APPEND | 0x400 | open file to append |
### close
Informs filesystem provider, that a file is closed.
Since `close` is a notification, it cannot fail.
webfuse daemon: {"method": "close", "params": [<filesystem>, <inode>, <handle>, <flags>], "id": <id>}
| Item | Data type | Description |
| ----------- | ----------| ---------------------------- |
| filesystem | string | name of the filesystem |
| inode | integer | inode of the file |
| handle | integer | handle of the file |
| flags | integer | access mode flags (see open) |
### read
Read from an open file.
webfuse daemon: {"method": "close", "params": [<filesystem>, <inode>, <handle>, <offset>, <length>], "id": <id>}
fs provider: {"result": {
"data": <data>,
"format": <format>,
"count": <count>
}, "id": <id>}
| Item | Data type | Description |
| ----------- | ----------| ----------------------------- |
| filesystem | string | name of the filesystem |
| inode | integer | inode of the file |
| handle | integer | handle of the file |
| offset | integer | Offet to start read operation |
| length | integer | Max. number of bytes to read |
| data | integer | handle of the file |
| format | string | Encoding of data (see below) |
| count | integer | Actual number of bytes read |
#### Format
| Format | Description |
| ---------- | -------------------------------------------------------- |
| "identiy" | Use data as is; note that JSON strings are UTF-8 encoded |
| "base64" | data is base64 encoded |
## Requests (Provider -> Adapter)
### add_filesystem
Adds a filesystem.
fs provider: {"method": "add_filesystem", "params": [<name>], "id": <id>}
webfuse daemon: {"result": {"id": <name>}, "id": <id>}
| Item | Data type | Description |
| ----------- | ----------| ------------------------------- |
| name | string | name and id of filesystem |
### authtenticate
Authenticate the provider.
If authentication is enabled, a provider must be authenticated by the adapter before filesystems can be added.
fs provider: {"method": "authenticate", "params": [<type>, <credentials>], "id": <id>}
webfuse daemon: {"result": {}, "id": <id>}
| Item | Data type | Description |
| ----------- | ----------| ------------------------------- |
| type | string | authentication type (see below) |
| credentials | object | credentials to authenticate |
#### authentication types
- **username**: authenticate via username and password
`{"username": <username>, "password": <password>}`

@ -1,196 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdbool.h>
#include <signal.h>
#include <unistd.h>
#include <getopt.h>
#include <webfuse_adapter.h>
#include <userdb.h>
#define SERVICE_TIMEOUT (1 * 1000)
struct args
{
struct wf_server_config * config;
char * passwd_path;
bool show_help;
};
static bool shutdown_requested = false;
static void show_help(void)
{
printf(
"webfused, Copyright (c) 2019, webfuse authors <https://github.com/falk-werner/webfuse>\n"
"Websocket file system daemon\n"
"\n"
"Usage: webfused [m <mount_point>] [-d <document_root] [-n <vhost_name>] [-p <port>]\n"
" [-c <server_cert_path>] [-k <server_key_path>] [-P <passwd_path>]\n"
"\n"
"Options:\n"
"\t-m, --mount_point Path of mount point (required)\n"
"\t-d, --document_root Path of www directory (default: not set, www disabled)\n"
"\t-c, --server_cert_path Path of servers own certificate (default: not set, TLS disabled)\n"
"\t-k, --server_key_path Path of servers private key (default: not set, TLS disabled)\n"
"\t-n, --vhost_name Name of virtual host (default: \"localhost\")\n"
"\t-p, --port Number of servers port (default: 8080)\n"
"\t-P, --passwd_path Path to password file (default: not set, authentication disabled)\n"
"\n");
}
static bool authenticate(struct wf_credentials * creds, void * user_data)
{
bool result = false;
struct args * args = user_data;
char const * username = wf_credentials_get(creds, "username");
char const * password = wf_credentials_get(creds, "password");
if ((NULL != username) && (NULL != password))
{
struct userdb * db = userdb_create("");
result = userdb_load(db, args->passwd_path);
if (result)
{
result = userdb_check(db, username, password);
}
userdb_dispose(db);
}
return result;
}
static int parse_arguments(int argc, char * argv[], struct args * args)
{
static struct option const options[] =
{
{"mount_point", required_argument, NULL, 'm'},
{"document_root", required_argument, NULL, 'd'},
{"server_cert_path", required_argument, NULL, 'c'},
{"server_key_path", required_argument, NULL, 'k'},
{"vhost_name", required_argument, NULL, 'n'},
{"port", required_argument, NULL, 'p'},
{"passwd_path", required_argument, NULL, 'P'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
bool result = EXIT_SUCCESS;
bool finished = false;
bool has_mountpoint = false;
while ((!finished) && (EXIT_SUCCESS == result))
{
int option_index = 0;
int const c = getopt_long(argc, argv, "m:d:c:k:n:p:P:h", options, &option_index);
switch (c)
{
case -1:
finished = true;
break;
case 'h':
args->show_help = true;
finished = true;
break;
case 'm':
wf_server_config_set_mountpoint(args->config, optarg);
has_mountpoint = true;
break;
case 'd':
wf_server_config_set_documentroot(args->config, optarg);
break;
case 'c':
wf_server_config_set_certpath(args->config, optarg);
break;
case 'k':
wf_server_config_set_keypath(args->config, optarg);
break;
case 'n':
wf_server_config_set_vhostname(args->config, optarg);
break;
case 'p':
wf_server_config_set_port(args->config, atoi(optarg));
break;
case 'P':
free(args->passwd_path);
args->passwd_path = strdup(optarg);
wf_server_config_add_authenticator(args->config,
"username",
&authenticate,
args);
break;
default:
fprintf(stderr, "error: unknown argument\n");
result = EXIT_FAILURE;
break;
}
}
if ((EXIT_SUCCESS == result) && (!args->show_help))
{
if (!has_mountpoint)
{
fprintf(stderr, "error: missing mount point\n");
result = EXIT_FAILURE;
}
}
if (EXIT_SUCCESS != result)
{
args->show_help = true;
}
return result;
}
static void on_interrupt(int signal_id)
{
(void) signal_id;
shutdown_requested = true;
}
int main(int argc, char * argv[])
{
struct args args;
args.config = wf_server_config_create();
wf_server_config_set_vhostname(args.config, "localhost");
wf_server_config_set_port(args.config, 8080);
args.passwd_path = NULL;
args.show_help = false;
int result = parse_arguments(argc, argv, &args);
if (!args.show_help)
{
signal(SIGINT, on_interrupt);
struct wf_server * server = wf_server_create(args.config);
if (NULL != server)
{
while (!shutdown_requested)
{
wf_server_service(server, SERVICE_TIMEOUT);
}
wf_server_dispose(server);
}
else
{
fprintf(stderr, "fatal: unable start server\n");
result = EXIT_FAILURE;
}
}
else
{
show_help();
}
free(args.passwd_path);
wf_server_config_dispose(args.config);
return result;
}

@ -1,18 +0,0 @@
<html>
<head>
<title>WebFuse Example</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="style/main.css">
<script type="module" src="js/startup.js"></script>
</head>
<body>
<div class="page">
<div class="window">
<div class="title">Connection</div>
<div id="connection"></div>
</div>
</div>
</body>
</html>

@ -1,287 +0,0 @@
module.exports = {
"env": {
"browser": true,
"es6": true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"rules": {
"accessor-pairs": "error",
"array-bracket-newline": "error",
"array-bracket-spacing": "error",
"array-callback-return": "error",
"array-element-newline": ["error", "consistent"],
"arrow-body-style": "error",
"arrow-parens": [
"error",
"always"
],
"arrow-spacing": [
"error",
{
"after": true,
"before": true
}
],
"block-scoped-var": "error",
"block-spacing": [
"error",
"always"
],
"brace-style": "off",
"callback-return": "off",
"camelcase": "error",
"capitalized-comments": [
"error",
"never"
],
"class-methods-use-this": "off",
"comma-dangle": "error",
"comma-spacing": [
"error",
{
"after": true,
"before": false
}
],
"comma-style": [
"error",
"last"
],
"complexity": "error",
"computed-property-spacing": [
"error",
"never"
],
"consistent-return": "error",
"consistent-this": "error",
"curly": "error",
"default-case": "error",
"dot-location": "error",
"dot-notation": "error",
"eol-last": "off",
"eqeqeq": "off",
"func-call-spacing": "error",
"func-name-matching": "error",
"func-names": "error",
"func-style": [
"error",
"declaration"
],
"function-paren-newline": "error",
"generator-star-spacing": "error",
"global-require": "error",
"guard-for-in": "error",
"handle-callback-err": "error",
"id-blacklist": "error",
"id-length": "error",
"id-match": "error",
"implicit-arrow-linebreak": [
"error",
"beside"
],
"indent": "off",
"indent-legacy": "off",
"init-declarations": "off",
"jsx-quotes": "error",
"key-spacing": "off",
"keyword-spacing": "off",
"line-comment-position": "error",
"linebreak-style": [
"error",
"unix"
],
"lines-around-comment": "error",
"lines-around-directive": "error",
"lines-between-class-members": "off",
"max-classes-per-file": "error",
"max-depth": "error",
"max-len": "off",
"max-lines": "error",
"max-lines-per-function": "off",
"max-nested-callbacks": "error",
"max-params": "off",
"max-statements": "off",
"max-statements-per-line": "off",
"multiline-comment-style": "error",
"new-cap": "error",
"new-parens": "error",
"newline-after-var": "off",
"newline-before-return": "error",
"newline-per-chained-call": "error",
"no-alert": "error",
"no-array-constructor": "error",
"no-async-promise-executor": "error",
"no-await-in-loop": "error",
"no-bitwise": "off",
"no-buffer-constructor": "error",
"no-caller": "error",
"no-catch-shadow": "error",
"no-confusing-arrow": "error",
"no-continue": "error",
"no-div-regex": "error",
"no-duplicate-imports": "error",
"no-else-return": "off",
"no-empty-function": "off",
"no-eq-null": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-label": "error",
"no-extra-parens": "off",
"no-floating-decimal": "error",
"no-implicit-coercion": "error",
"no-implicit-globals": "off",
"no-implied-eval": "error",
"no-inline-comments": "error",
"no-invalid-this": "error",
"no-iterator": "error",
"no-label-var": "error",
"no-labels": "error",
"no-lone-blocks": "error",
"no-lonely-if": "error",
"no-loop-func": "error",
"no-magic-numbers": "off",
"no-misleading-character-class": "error",
"no-mixed-operators": "error",
"no-mixed-requires": "error",
"no-multi-assign": "error",
"no-multi-spaces": "off",
"no-multi-str": "error",
"no-multiple-empty-lines": "error",
"no-native-reassign": "error",
"no-negated-condition": "off",
"no-negated-in-lhs": "error",
"no-nested-ternary": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-object": "error",
"no-new-require": "error",
"no-new-wrappers": "error",
"no-octal-escape": "error",
"no-param-reassign": "error",
"no-path-concat": "error",
"no-plusplus": "error",
"no-process-env": "error",
"no-process-exit": "error",
"no-proto": "error",
"no-prototype-builtins": "error",
"no-restricted-globals": "error",
"no-restricted-imports": "error",
"no-restricted-modules": "error",
"no-restricted-properties": "error",
"no-restricted-syntax": "error",
"no-return-assign": "error",
"no-return-await": "error",
"no-script-url": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow": "off",
"no-shadow-restricted-names": "error",
"no-spaced-func": "error",
"no-sync": "error",
"no-tabs": "off",
"no-template-curly-in-string": "error",
"no-ternary": "off",
"no-throw-literal": "error",
"no-trailing-spaces": "off",
"no-undef-init": "error",
"no-undefined": "error",
"no-unmodified-loop-condition": "error",
"no-unneeded-ternary": "error",
"no-unused-expressions": "error",
"no-use-before-define": "error",
"no-useless-call": "error",
// "no-useless-catch": "error",
"no-useless-computed-key": "error",
"no-useless-concat": "error",
"no-useless-constructor": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-var": "error",
"no-void": "error",
"no-warning-comments": "error",
"no-whitespace-before-property": "error",
"no-with": "error",
"nonblock-statement-body-position": "error",
"object-curly-newline": "error",
"object-curly-spacing": "off",
"object-shorthand": "off",
"one-var": "off",
"one-var-declaration-per-line": "error",
"operator-assignment": "error",
"operator-linebreak": "error",
"padded-blocks": "off",
"padding-line-between-statements": "error",
"prefer-arrow-callback": "error",
"prefer-const": "off",
"prefer-destructuring": "off",
"prefer-numeric-literals": "off",
"prefer-object-spread": "error",
"prefer-promise-reject-errors": "error",
"prefer-reflect": "error",
"prefer-rest-params": "error",
"prefer-spread": "error",
"prefer-template": "error",
"quote-props": "off",
"quotes": "off",
"radix": "error",
"require-atomic-updates": "error",
"require-await": "off",
"require-jsdoc": "off",
"require-unicode-regexp": "off",
"rest-spread-spacing": "error",
"semi": "error",
"semi-spacing": "error",
"semi-style": [
"error",
"last"
],
"sort-imports": "error",
"sort-keys": "off",
"sort-vars": "error",
"space-before-blocks": "error",
"space-before-function-paren": "off",
"space-in-parens": [
"error",
"never"
],
"space-infix-ops": "error",
"space-unary-ops": [
"error",
{
"nonwords": false,
"words": false
}
],
"spaced-comment": [
"error",
"always"
],
"strict": [
"error",
"never"
],
"switch-colon-spacing": "error",
"symbol-description": "error",
"template-curly-spacing": "error",
"template-tag-spacing": "error",
"unicode-bom": [
"error",
"never"
],
"valid-jsdoc": "error",
"vars-on-top": "error",
"wrap-iife": "error",
"wrap-regex": "error",
"yield-star-spacing": "error",
"yoda": "off"
}
};

@ -1,93 +0,0 @@
export class ConnectionView {
constructor(client, provider) {
this._provider = provider;
this._client = client;
this._client.onopen = () => { this._onConnectionOpened(); };
this._client.onclose = () => { this._onConnectionClosed(); };
this.element = document.createElement("div");
const connectBox = document.createElement("div");
this.element.appendChild(connectBox);
const urlLabel = document.createElement("span");
urlLabel.textContent = "URL:";
connectBox.appendChild(urlLabel);
this.urlTextbox = document.createElement("input");
this.urlTextbox.type = "text";
this.urlTextbox.value = window.location.href.replace(/^http/, "ws");
connectBox.appendChild(this.urlTextbox);
this.connectButton = document.createElement("input");
this.connectButton.type = "button";
this.connectButton.value = "connect";
this.connectButton.addEventListener("click", () => { this._onConnectButtonClicked(); });
connectBox.appendChild(this.connectButton);
const authenticateBox = document.createElement("div");
this.element.appendChild(authenticateBox);
const authLabel = document.createElement("span");
authLabel.textContent = "use authentication:";
authenticateBox.appendChild(authLabel);
this.authenticateCheckbox = document.createElement("input");
this.authenticateCheckbox.type = "checkbox";
authenticateBox.appendChild(this.authenticateCheckbox);
const usernameLabel = document.createElement("span");
usernameLabel.textContent = "user:";
authenticateBox.appendChild(usernameLabel);
this.usernameTextbox = document.createElement("input");
this.usernameTextbox.type = "text";
this.usernameTextbox.value = "bob";
authenticateBox.appendChild(this.usernameTextbox);
const passwordLabel = document.createElement("span");
passwordLabel.textContent = "user:";
authenticateBox.appendChild(passwordLabel);
this.passwordTextbox = document.createElement("input");
this.passwordTextbox.type = "password";
this.passwordTextbox.value = "secret";
authenticateBox.appendChild(this.passwordTextbox);
}
_onConnectButtonClicked() {
if (!this._client.isConnected()) {
let url = this.urlTextbox.value;
this._client.connectTo(url);
}
else {
this._client.disconnect();
}
}
_onAuthenticateButtonClicked() {
if (this._client.isConnected()) {
}
}
_onConnectionOpened() {
if (this.authenticateCheckbox.checked) {
const username = this.usernameTextbox.value;
const password = this.passwordTextbox.value;
const promise = this._client.authenticate("username", { username, password });
promise.then(() => { this._client.addProvider("test", this._provider); });
} else {
this._client.addProvider("test", this._provider);
}
this.connectButton.value = "disconnect";
}
_onConnectionClosed() {
this.connectButton.value = "connect";
}
}

@ -1,122 +0,0 @@
/* eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }] */
import { BadState } from "./webfuse/bad_state.js";
import { FileMode } from "./webfuse/file_mode.js";
import { Provider } from "./webfuse/provider.js";
export class FileSystemProvider extends Provider {
constructor(root) {
super();
this.root = root;
this._inodes = { };
this._walk(this.root, (entry) => { this._inodes[entry.inode] = entry; });
}
_walk(node, callback) {
callback(node);
const entries = node.entries;
if (entries) {
for(let entry of Object.entries(entries)) {
this._walk(entry[1], callback);
}
}
}
async lookup(parent, name) {
const parentEntry = this._inodes[parent];
const entry = (parentEntry && parentEntry.entries && parentEntry.entries[name]) || null;
if (entry) {
return {
inode: entry.inode,
mode: entry.mode || parseInt("755", 8),
type: entry.type || "file",
size: entry.size || (entry.contents && entry.contents.length) || 0,
atime: entry.atime || 0,
mtime: entry.mtime || 0,
ctime: entry.ctime || 0
};
}
else {
throw new BadState(BadState.NO_ENTRY);
}
}
async getattr(inode) {
let entry = this._inodes[inode];
if (entry) {
return {
mode: entry.mode || parseInt("755", 8),
type: entry.type || "file",
size: entry.size || (entry.contents && entry.contents.length) || 0,
atime: entry.atime || 0,
mtime: entry.mtime || 0,
ctime: entry.ctime || 0
};
}
else {
throw new BadState(BadState.NO_ENTRY);
}
}
async readdir(inode) {
let entry = this._inodes[inode];
if ((entry) && ("dir" === entry.type)) {
let result = [
{name: ".", inode: entry.inode},
{name: "..", inode: entry.inode}
];
for(let subdir of Object.entries(entry.entries)) {
const name = subdir[0];
const inode = subdir[1].inode;
result.push({name, inode});
}
return result;
}
else {
throw new BadState(BadState.NO_ENTRY);
}
}
async open(inode, mode) {
let entry = this._inodes[inode];
if (entry.type === "file") {
if ((mode & FileMode.ACCESS_MODE) === FileMode.READONLY) {
return {handle: 1337};
}
else {
throw new BadState(BadState.NO_ACCESS);
}
}
else {
throw new BadState(BadState.NO_ENTRY);
}
}
close(_inode, _handle, _mode) {
// do nothing
return true;
}
async read(inode, handle, offset, length) {
let entry = this._inodes[inode];
if (entry.type === "file") {
const end = Math.min(offset + length, entry.contents.length);
const data = (offset < entry.contents.length) ? entry.contents.substring(offset, end) : "";
return data;
}
else {
throw new BadState(BadState.NO_ENTRY);
}
}
}

@ -1,11 +0,0 @@
{
"name": "webfuse-provider",
"version": "0.2.0",
"description": "Provider for websocket filesystem (webfuse)",
"main": "startup.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Falk Werner",
"license": "LGPL-3.0"
}

@ -1,25 +0,0 @@
import { Client } from "./webfuse/client.js";
import { ConnectionView } from "./connection_view.js";
import { FileSystemProvider } from "./filesystem_provider.js";
function mode(value) {
return parseInt(value, 8);
}
function startup() {
const provider = new FileSystemProvider({
inode: 1,
mode: mode("0755"),
type: "dir",
entries: {
"hello.txt" : { inode: 2, mode: mode("0444"), type: "file", contents: "Hello, World!"},
"say_hello.sh": { inode: 3, mode: mode("0555"), type: "file", contents: "#!/bin/sh\necho hello\n"}
}
});
const client = new Client();
const connectionView = new ConnectionView(client, provider);
document.getElementById('connection').appendChild(connectionView.element);
}
window.onload = startup;

@ -1,15 +0,0 @@
export class BadState extends Error {
static get BAD() { return 1; }
static get NOT_IMPLEMENTED() { return 2; }
static get TIMEOUT() { return 3; }
static get FORMAT() { return 4; }
static get NO_ENTRY() { return 101; }
static get NO_ACCESS() { return 102; }
constructor(code) {
super("Bad State");
this.code = code;
}
}

@ -1,223 +0,0 @@
import { BadState } from "./bad_state.js";
export class Client {
static get _PROTOCOL() { return "fs"; }
constructor(provider) {
this._provider = { };
this._pendingRequests = {};
this._id = 0;
this._ws = null;
this.onopen = () => { };
this.onclose = () => { };
this.onerror = () => { };
}
connectTo(url) {
this.disconnect();
this._ws = new WebSocket(url, Client._PROTOCOL);
this._ws.onopen = this.onopen;
this._ws.onclose = this.onclose;
this._ws.onerror = this.onerror;
this._ws.onmessage = (message) => {
this._onmessage(message);
};
}
_invokeRequest(method, params) {
this._id += 1;
const id = this._id;
const request = {method, params, id};
return new Promise((resolve, reject) => {
this._pendingRequests[id] = {resolve, reject};
this._ws.send(JSON.stringify(request));
});
}
authenticate(type, credentials) {
return this._invokeRequest("authenticate", [type, credentials]);
}
addProvider(name, provider) {
this._provider[name] = provider;
const request = {
"method": "add_filesystem",
"params": [name],
"id": 23
};
this._ws.send(JSON.stringify(request));
}
disconnect() {
if (this._ws) {
this._ws.close();
this._ws = null;
}
}
isConnected() {
return ((this._ws) && (this._ws.readyState === WebSocket.OPEN));
}
_isRequest(request) {
const method = request.method;
return (("string" === typeof(method)) && ("params" in request));
}
_isResponse(response) {
const id = response.id;
return (("number" === typeof(id)) && (("result" in response) || ("error" in response)));
}
_removePendingRequest(id) {
let result = null;
if (id in this._pendingRequests) {
result = this._pendingRequests[id];
Reflect.deleteProperty(this._pendingRequests, id);
}
return result;
}
_onmessage(message) {
try {
const data = JSON.parse(message.data);
if (this._isRequest(data)) {
const method = data.method;
const id = data.id;
const params = data.params;
if ("number" === typeof(id)) {
this._invoke(method, params, id);
}
else {
this._notify(method, params);
}
}
else if (this._isResponse(data)) {
const id = data.id;
const result = data.result;
const error = data.error;
const request = this._removePendingRequest(id);
if (request) {
if (result) {
request.resolve(result);
}
else {
request.reject(error);
}
}
}
}
catch (ex) {
// swallow
}
}
_invoke(method, params, id) {
this._invokeAsync(method, params).
then((result) => {
const response = { result, id };
this._ws.send(JSON.stringify(response));
}).
catch((ex) => {
const code = ex.code || BadState.BAD;
const response = {error: {code}, id};
this._ws.send(JSON.stringify(response));
});
}
async _invokeAsync(method, params) {
switch(method)
{
case "lookup":
return this._lookup(params);
case "getattr":
return this._getattr(params);
case "readdir":
return this._readdir(params);
case "open":
return this._open(params);
case "read":
return this._read(params);
default:
throw new BadState(BadState.NOT_IMPLEMENTED);
}
}
_notify(method, params) {
switch(method) {
case 'close':
this._close(params);
break;
default:
throw new Error(`Invalid method: "${method}"`);
}
}
_getProvider(name) {
if (name in this._provider) {
return this._provider[name];
}
else {
throw new Error('Unknown provider');
}
}
async _lookup([providerName, parent, name]) {
const provider = this._getProvider(providerName);
return provider.lookup(parent, name);
}
async _getattr([providerName, inode]) {
const provider = this._getProvider(providerName);
return provider.getattr(inode);
}
async _readdir([providerName, inode]) {
const provider = this._getProvider(providerName);
return provider.readdir(inode);
}
async _open([providerName, inode, mode]) {
const provider = this._getProvider(providerName);
return provider.open(inode, mode);
}
_close([providerName, inode, handle, mode]) {
const provider = this._getProvider(providerName);
provider.close(inode, handle, mode);
}
async _read([providerName, inode, handle, offset, length]) {
const provider = this._getProvider(providerName);
const data = await provider.read(inode, handle, offset, length);
if ("string" === typeof(data)) {
return {
data: btoa(data),
format: "base64",
count: data.length
};
}
else {
throw new BadState(BadState.BAD);
}
}
}

@ -1,10 +0,0 @@
export class FileMode {
static get ACCESS_MODE() { return 0x003; }
static get READONLY() { return 0x000; }
static get WRITEONLY() { return 0x001; }
static get READWRITE() { return 0x002; }
static get CREATE() { return 0x040; }
static get EXCLUSIVE() { return 0x080; }
static get TRUNKATE() { return 0x200; }
static get APPEND() { return 0x400; }
}

@ -1,30 +0,0 @@
/* eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }] */
import { BadState } from "./bad_state.js";
export class Provider {
async lookup(_parent, _name) {
throw new BadState(BadState.NOT_IMPLEMENTED);
}
async getattr(_inode) {
throw new BadState(BadState.NOT_IMPLEMENTED);
}
async readdir(_inode) {
throw new BadState(BadState.NOT_IMPLEMENTED);
}
async open(_inode, _mode) {
throw new BadState(BadState.NOT_IMPLEMENTED);
}
close(_inode, _handle, _mode) {
// empty
}
async read(_inode, _handle, _offset, _length) {
throw new BadState(BadState.NOT_IMPLEMENTED);
}
}

@ -1,47 +0,0 @@
html, body {
font-family: monospace;
background-color: #c0c0c0;
}
.page {
margin-left: 50px;
margin-right: 50px;
width: auto;
}
.window {
border: 1px solid black;
background-color: black;
border-radius: 5px;
padding: 10px;
margin-bottom: 25px;
color: white;
}
.window .title {
text-align: center;
color: #dba329;
font-weight: bold;
padding-bottom: 10px;
margin-bottom: 10px;
border-bottom: 1px solid #dba329;
}
.commands {
text-align: right;
}
.content {
column-count: 2;
column-width: 50%;
}
.content > div {
display: inline-block;
width: 100%;
}
#connection {
text-align: center;
}

@ -1,46 +0,0 @@
#ifndef USERDB_H
#define USERDB_H
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
extern "C"
{
#endif
struct userdb;
extern struct userdb * userdb_create(
char const * pepper);
extern void userdb_dispose(struct userdb * db);
extern bool userdb_save(
struct userdb * db,
char const * filename);
extern bool userdb_load(
struct userdb * db,
char const * filename);
extern void userdb_add(
struct userdb * db,
char const * username,
char const * password);
extern void userdb_remove(
struct userdb * db,
char const * user);
extern bool userdb_check(
struct userdb * db,
char const * username,
char const * password);
#ifdef __cplusplus
}
#endif
#endif

@ -1,277 +0,0 @@
#include "userdb.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jansson.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#define USERDB_HASH_ALGORITHM "sha512"
#define USERDB_MAJOR 1
#define USERDB_MINOR 0
#define USERDB_SALT_SIZE 32
struct userdb
{
json_t * users;
char * pepper;
char * hash_algorithm;
};
static bool is_compatible(json_t * meta)
{
bool result = false;
if (json_is_object(meta))
{
json_t * type = json_object_get(meta, "type");
json_t * major = json_object_get(meta, "major");
json_t * minor = json_object_get(meta, "minor");
json_t * hash_algorithm = json_object_get(meta, "hash_algorithm");
result = (
json_is_string(type) &&
(0 == strcmp(json_string_value(type), "wf-userdb")) &&
json_is_integer(major) &&
(USERDB_MAJOR == json_integer_value(major)) &&
json_is_integer(minor) &&
json_is_string(hash_algorithm)
);
if (result)
{
char const * algorithm = json_string_value(hash_algorithm);
result = (NULL != EVP_get_digestbyname(algorithm));
}
}
return result;
}
static char hex_char(unsigned char value)
{
switch (value)
{
case 0x00: return '0';
case 0x01: return '1';
case 0x02: return '2';
case 0x03: return '3';
case 0x04: return '4';
case 0x05: return '5';
case 0x06: return '6';
case 0x07: return '7';
case 0x08: return '8';
case 0x09: return '9';
case 0x0a: return 'a';
case 0x0b: return 'b';
case 0x0c: return 'c';
case 0x0d: return 'd';
case 0x0e: return 'e';
case 0x0f: return 'f';
default: return '?';
}
}
static char * to_hex(unsigned char const * value, size_t length)
{
char * result = malloc((2 * length) + 1);
if (NULL != result)
{
for (size_t i = 0, j = 0; i < length; i++, j+=2)
{
unsigned char high = (value[i] >> 4) & 0x0f;
unsigned char low = value[i] & 0x0f;
result[j ] = hex_char(high);
result[j + 1] = hex_char(low);
}
result[2 * length] = '\0';
}
return result;
}
static char * generate_salt(void)
{
unsigned char buffer[USERDB_SALT_SIZE];
int rc = RAND_bytes(buffer, USERDB_SALT_SIZE);
if (1 != rc)
{
fprintf(stderr, "fatal: failed to generate salt (OpenSSL RAND_bytes failed)\n");
exit(EXIT_FAILURE);
}
return to_hex(buffer, USERDB_SALT_SIZE);
}
static char * compute_hash(
struct userdb * db,
char const * password,
char const * salt)
{
EVP_MD const * digest = EVP_get_digestbyname(db->hash_algorithm);
if (NULL == digest)
{
fprintf(stderr, "error: hash algorithm %s not supported\n", db->hash_algorithm);
return NULL;
}
char * result = NULL;
unsigned int hash_size = EVP_MD_size(digest);
unsigned char * hash = malloc(hash_size);
if (NULL != hash)
{
EVP_MD_CTX * context = EVP_MD_CTX_new();
EVP_DigestInit_ex(context, digest, NULL);
EVP_DigestUpdate(context, password, strlen(password));
EVP_DigestUpdate(context, salt, strlen(salt));
EVP_DigestUpdate(context, db->pepper, strlen(db->pepper));
EVP_DigestFinal_ex(context, hash, &hash_size);
EVP_MD_CTX_free(context);
result = to_hex(hash, hash_size);
free(hash);
}
return result;
}
struct userdb * userdb_create(
char const * pepper)
{
struct userdb * db = malloc(sizeof(struct userdb));
if (NULL != db)
{
db->users = json_object();
db->pepper = strdup(pepper);
db->hash_algorithm = strdup(USERDB_HASH_ALGORITHM);
}
return db;
}
void userdb_dispose(
struct userdb * db)
{
json_decref(db->users);
free(db->pepper);
free(db->hash_algorithm);
free(db);
}
bool userdb_save(
struct userdb * db,
char const * filename)
{
json_t * container = json_object();
json_t * meta = json_object();
json_object_set_new(meta, "type", json_string("wf-userdb"));
json_object_set_new(meta, "major", json_integer(USERDB_MAJOR));
json_object_set_new(meta, "minor", json_integer(USERDB_MINOR));
json_object_set_new(meta, "hash_algorithm", json_string(db->hash_algorithm));
json_object_set_new(container, "meta", meta);
json_object_set(container, "users", db->users);
int result = json_dump_file(container, filename, JSON_INDENT(2));
json_decref(container);
return (0 == result);
}
bool userdb_load(
struct userdb * db,
char const * filename)
{
bool result = false;
json_t * container = json_load_file(filename, 0, NULL);
if (NULL != container)
{
json_t * meta = json_object_get(container, "meta");
json_t * users = json_object_get(container, "users");
if ((is_compatible(meta)) && (json_is_object(users))) {
json_t * hash_algorithm = json_object_get(meta, "hash_algorithm");
free(db->hash_algorithm);
db->hash_algorithm = strdup(json_string_value(hash_algorithm));
json_decref(db->users);
json_incref(users);
db->users = users;
result = true;
}
json_decref(container);
}
return result;
}
void userdb_add(
struct userdb * db,
char const * username,
char const * password)
{
char * salt = generate_salt();
char * hash = compute_hash(db, password, salt);
json_t * user = json_object();
json_object_set_new(user, "password_hash", json_string(hash));
json_object_set_new(user, "salt", json_string(salt));
json_object_set_new(db->users, username, user);
free(salt);
free(hash);
}
void userdb_remove(
struct userdb * db,
char const * user)
{
json_object_del(db->users, user);
}
static char const * json_object_get_string(
json_t * object,
char const * key)
{
char const * result = NULL;
json_t * string_holder = json_object_get(object, key);
if (json_is_string(string_holder))
{
result = json_string_value(string_holder);
}
return result;
}
bool userdb_check(
struct userdb * db,
char const * username,
char const * password)
{
bool result = false;
json_t * user = json_object_get(db->users, username);
if (json_is_object(user))
{
char const * salt = json_object_get_string(user, "salt");
char const * hash = json_object_get_string(user, "password_hash");
char * computed_hash = compute_hash(db, password, salt);
result = (0 == strcmp(computed_hash, hash));
free(computed_hash);
}
return result;
}

@ -1,304 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <getopt.h>
#include <openssl/conf.h>
#include <openssl/opensslv.h>
#include <openssl/engine.h>
#include <openssl/evp.h>
#include <jansson.h>
#include <userdb.h>
struct args
{
char * file;
char * command;
char * username;
char * password;
char * pepper;
bool show_help;
};
typedef int command_invoke_fn(
struct args * args);
struct command
{
char const * name;
command_invoke_fn * invoke;
};
static void print_usage(void)
{
printf(
"webfuse-passwd, Copyright (c) 2019, webfuse authors <https://github.com/falk-werner/webfuse>\n"
"Manage webfuse passwd file\n"
"\n"
"Usage: webfuse-passwd -f <file> -c <command> [-u <username>] [-p <password>] [-P <pepper>]\n"
"\n"
"Options:\n"
"\t-f, --file Path of wf passwd file\n"
"\t-c, --command Command to execute\n"
"\t-u, --username Name of user\n"
"\t-p, --password Password of user\n"
"\t-P, --pepper pepper\n"
"\t-h, --help Shows this message\n"
"\n"
"Commands:\n"
"\tcreate Creates an empty passwd file (or cleans an existing)\n"
"\t Example: webfuse-passwd -f passwd.json -c create\n"
"\tadd Adds or replaces a user\n"
"\t Example: webfuse-passwd -f passwd.json -c add -u bob -p secret\n"
"\tremove Removes a user\n"
"\t Example: webfuse-passwd -f passwd.json -c remove -u bob\n"
"\tcheck Checks password of a user\n"
"\t Example: webfuse-passwd -f passwd.json -c check -u bob -p secret\n"
"\n"
);
}
static int parse_args(struct args * args, int argc, char * argv[])
{
static struct option const options[] =
{
{"file", required_argument, NULL, 'f'},
{"command", required_argument, NULL, 'c'},
{"username", required_argument, NULL, 'u'},
{"password", required_argument, NULL, 'p'},
{"Pepper", required_argument, NULL, 'P'},
{"help", required_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
int result = EXIT_SUCCESS;
bool finished = false;
while ((!finished) && (EXIT_SUCCESS == result))
{
int option_index = 0;
int const c = getopt_long(argc, argv, "f:c:u:p:P:h", options, &option_index);
switch (c)
{
case -1:
finished = true;
break;
case 'h':
args->show_help = true;
finished = true;
break;
case 'f':
free(args->file);
args->file = strdup(optarg);
break;
case 'c':
free(args->command);
args->command = strdup(optarg);
break;
case 'u':
free(args->username);
args->username = strdup(optarg);
break;
case 'p':
free(args->password);
args->password = strdup(optarg);
break;
case 'P':
free(args->pepper);
args->pepper = strdup(optarg);
break;
default:
fprintf(stderr, "error: unknown argument\n");
result = EXIT_FAILURE;
break;
}
}
if ((result == EXIT_SUCCESS) && (!args->show_help))
{
if (NULL == args->file)
{
fprintf(stderr, "error: missing file\n");
args->show_help = true;
result = EXIT_FAILURE;
}
else if (NULL == args->command)
{
fprintf(stderr, "error: missing command\n");
args->show_help = true;
result = EXIT_FAILURE;
}
}
return result;
}
static void args_init(struct args * args)
{
args->file = NULL;
args->command = NULL;
args->username = NULL;
args->password = NULL;
args->pepper = strdup("");
args->show_help = false;
}
static int create_passwd(struct args * args)
{
struct userdb * db = userdb_create(args->pepper);
bool result = userdb_save(db, args->file);
userdb_dispose(db);
return (result) ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int add_user(struct args * args)
{
if (NULL == args->username)
{
fprintf(stderr, "error: missing username");
args->show_help = true;
return EXIT_FAILURE;
}
if (NULL == args->password)
{
fprintf(stderr, "error: missing password");
args->show_help = true;
return EXIT_FAILURE;
}
struct userdb * db = userdb_create(args->pepper);
userdb_load(db, args->file);
userdb_add(db, args->username, args->password);
bool result = userdb_save(db, args->file);
userdb_dispose(db);
return (result) ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int remove_user(struct args * args)
{
if (NULL == args->username)
{
fprintf(stderr, "error: missing username");
args->show_help = true;
return EXIT_FAILURE;
}
struct userdb * db = userdb_create(args->pepper);
userdb_load(db, args->file);
userdb_remove(db, args->username);
bool result = userdb_save(db, args->file);
userdb_dispose(db);
return (result) ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int check_password(struct args * args)
{
if (NULL == args->username)
{
fprintf(stderr, "error: missing username");
args->show_help = true;
return EXIT_FAILURE;
}
if (NULL == args->password)
{
fprintf(stderr, "error: missing password");
args->show_help = true;
return EXIT_FAILURE;
}
struct userdb * db = userdb_create(args->pepper);
userdb_load(db, args->file);
bool result = userdb_check(db, args->username, args->password);
userdb_dispose(db);
printf("%s\n", (result) ? "OK" : "FAILURE");
return (result) ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int invoke_invalid_command(struct args * args)
{
(void) args;
fprintf(stderr, "error: unknown command\n");
return EXIT_FAILURE;
}
static struct command const commands[] =
{
{"create", &create_passwd},
{"add", &add_user},
{"remove", &remove_user},
{"check", &check_password},
{NULL, NULL}
};
static struct command const invalid_command =
{
"<invalid>",
&invoke_invalid_command
};
static struct command const * get_command(char const * name)
{
for(size_t i = 0; NULL != commands[i].name; i++)
{
if (0 == strcmp(name, commands[i].name))
{
return &commands[i];
}
}
return &invalid_command;
}
static void args_cleanup(struct args * args)
{
free(args->file);
free(args->command);
free(args->username);
free(args->password);
free(args->pepper);
}
static void openssl_cleanup(void)
{
FIPS_mode_set(0);
ENGINE_cleanup();
CONF_modules_unload(1);
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
ERR_free_strings();
}
int main(int argc, char * argv[])
{
OPENSSL_init();
OPENSSL_add_all_algorithms_conf();
struct args args;
args_init(&args);
int result = parse_args(&args, argc, argv);
if ((EXIT_SUCCESS == result) && (!args.show_help))
{
struct command const * command = get_command(args.command);
result = command->invoke(&args);
}
if (args.show_help)
{
print_usage();
}
args_cleanup(&args);
openssl_cleanup();
return result;
}

@ -1,385 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>
#include "webfuse_provider.h"
#define SERVICE_TIMEOUT (1 * 1000)
struct config
{
char * url;
struct wfp_client_config * client_config;
bool show_help;
};
enum fs_entry_type
{
FS_FILE,
FS_DIR
};
struct fs_entry
{
ino_t parent;
ino_t inode;
char const * name;
int mode;
enum fs_entry_type type;
size_t content_length;
char const * content;
};
struct fs
{
struct fs_entry const * entries;
};
static void show_help()
{
printf(
"webfuse-provider, Copyright (c) 2019, webfuse authors <https://github.com/falk-werner/webfuse>\n"
"Example for websocket file system provider\n"
"\n"
"Usage: webfuse-provider -u <url> [-k <key_path>] [-c <cert_path>]\n"
"\n"
"Options:\n"
"\t-u, --url URL of webfuse server (required)\n"
"\t-k, --key_path Path to private key of provider (default: not set, TLS disabled)\n"
"\t-c, --cert_path Path to certificate of provider (defautl: not set, TLS disabled)\n"
"\t-h, --help prints this message\n"
"\n"
"Example:\n"
"\twebfuse-provider -u ws://localhost:8080/\n"
"\n"
);
}
static int parse_arguments(
int argc,
char* argv[],
struct config * config)
{
static struct option const options[] =
{
{"url", required_argument, NULL, 'u'},
{"key_path", required_argument, NULL, 'k'},
{"cert_path", required_argument, NULL, 'c'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
int result = EXIT_SUCCESS;
bool finished = false;
while (!finished)
{
int option_index = 0;
int const c = getopt_long(argc, argv, "u:k:c:h", options, &option_index);
switch (c)
{
case -1:
finished = true;
break;
case 'h':
config->show_help = true;
finished = true;
break;
case 'u':
free(config->url);
config->url = strdup(optarg);
break;
case 'k':
wfp_client_config_set_keypath(config->client_config, optarg);
break;
case 'c':
wfp_client_config_set_certpath(config->client_config, optarg);
break;
default:
fprintf(stderr, "error: unknown argument\n");
finished = true;
result = EXIT_FAILURE;
break;
}
if (NULL == config->url)
{
fprintf(stderr, "error: missing required argument \"-u\"\n");
result = EXIT_FAILURE;
}
if (result != EXIT_SUCCESS)
{
config->show_help = true;
}
}
return result;
}
static struct fs_entry const * fs_getentry(
struct fs * fs,
ino_t inode)
{
for (size_t i = 0; 0 != fs->entries[i].inode; i++)
{
struct fs_entry const * entry = &fs->entries[i];
if (inode == entry->inode)
{
return entry;
}
}
return NULL;
}
static struct fs_entry const * fs_getentry_byname(
struct fs * fs,
ino_t parent,
char const * name)
{
for( size_t i = 0; 0 != fs->entries[i].inode; i++)
{
struct fs_entry const * entry = &fs->entries[i];
if ((parent == entry->parent) && (0 == strcmp(name, entry->name)))
{
return entry;
}
}
return NULL;
}
static void fs_stat(
struct fs_entry const * entry,
struct stat * stat)
{
memset(stat, 0, sizeof(struct stat));
stat->st_ino = entry->inode;
stat->st_mode = entry->mode;
if (FS_DIR == entry->type)
{
stat->st_mode |= S_IFDIR;
}
if (FS_FILE == entry->type)
{
stat->st_mode |= S_IFREG;
stat->st_size = entry->content_length;
}
}
static void fs_lookup(
struct wfp_request * request,
ino_t parent,
char const * name,
void * user_data)
{
struct fs * fs = (struct fs*) user_data;
struct fs_entry const * entry = fs_getentry_byname(fs, parent, name);
if (NULL != entry)
{
struct stat stat;
fs_stat(entry, &stat);
wfp_respond_lookup(request, &stat);
}
else
{
wfp_respond_error(request, WF_BAD_NOENTRY);
}
}
static void fs_getattr(
struct wfp_request * request,
ino_t inode,
void * user_data)
{
struct fs * fs = (struct fs*) user_data;
struct fs_entry const * entry = fs_getentry(fs, inode);
if (NULL != entry)
{
struct stat stat;
fs_stat(entry, &stat);
wfp_respond_getattr(request, &stat);
}
else
{
wfp_respond_error(request, WF_BAD_NOENTRY);
}
}
static void fs_readdir(
struct wfp_request * request,
ino_t directory,
void * user_data)
{
struct fs * fs = (struct fs*) user_data;
struct fs_entry const * dir = fs_getentry(fs, directory);
if ((NULL != dir) && (FS_DIR == dir->type))
{
struct wfp_dirbuffer * buffer = wfp_dirbuffer_create();
wfp_dirbuffer_add(buffer, ".", dir->inode);
wfp_dirbuffer_add(buffer, "..", dir->inode);
for(size_t i = 0; 0 != fs->entries[i].inode; i++)
{
struct fs_entry const * entry = &fs->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 fs_open(
struct wfp_request * request,
ino_t inode,
int flags,
void * user_data)
{
struct fs * fs = (struct fs*) user_data;
struct fs_entry const * entry = fs_getentry(fs, inode);
if ((NULL != entry) && (FS_FILE == entry->type))
{
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 size_t min(size_t const a, size_t const b)
{
return (a < b) ? a : b;
}
static void fs_read(
struct wfp_request * request,
ino_t inode,
uint32_t handle,
size_t offset,
size_t length,
void * user_data)
{
(void) handle;
struct fs * fs = (struct fs*) user_data;
struct fs_entry const * entry = fs_getentry(fs, inode);
if ((NULL != entry) && (FS_FILE == entry->type))
{
if (entry->content_length > offset)
{
size_t const remaining = entry->content_length - offset;
size_t const count = min(remaining, length);
wfp_respond_read(request, &entry->content[offset], count);
}
else
{
wfp_respond_error(request, WF_BAD);
}
}
else
{
wfp_respond_error(request, WF_BAD_NOENTRY);
}
}
static volatile bool shutdown_requested = false;
static void on_interrupt(int signal_id)
{
(void) signal_id;
shutdown_requested = true;
}
int main(int argc, char* argv[])
{
struct config config;
config.url = NULL;
config.show_help = false;
config.client_config = wfp_client_config_create();
int result = parse_arguments(argc, argv, &config);
if (EXIT_SUCCESS == result)
{
static struct fs_entry const entries[]=
{
{.parent = 0, .inode = 1, .name = "<root>", .mode = 0555, .type = FS_DIR},
{
.parent = 1,
.inode = 2,
.name = "hello.txt",
.mode = 0444,
.type = FS_FILE,
.content="hello, world!",
.content_length = 13,
},
{.parent = 0, .inode = 0, .name = NULL}
};
struct fs fs =
{
.entries = entries
};
signal(SIGINT, &on_interrupt);
wfp_client_config_set_userdata(config.client_config, &fs);
wfp_client_config_set_onlookup(config.client_config, &fs_lookup);
wfp_client_config_set_ongetattr(config.client_config, &fs_getattr);
wfp_client_config_set_onreaddir(config.client_config, &fs_readdir);
wfp_client_config_set_onopen(config.client_config, &fs_open);
wfp_client_config_set_onread(config.client_config, &fs_read);
struct wfp_client * client = wfp_client_create(config.client_config);
wfp_client_connect(client, config.url);
while (!shutdown_requested)
{
wfp_client_service(client, SERVICE_TIMEOUT);
}
wfp_client_dispose(client);
}
if (config.show_help)
{
show_help();
}
free(config.url);
wfp_client_config_dispose(config.client_config);
return result;
}

@ -1,104 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <signal.h>
#include "webfuse_provider.h"
#define SERVICE_TIMEOUT (1 * 1000)
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 volatile bool shutdown_requested = false;
static void on_interrupt(int signal_id)
{
(void) signal_id;
shutdown_requested = true;
}
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!");
struct wfp_client * client = wfp_client_create(config);
wfp_client_connect(client, args.url);
while (!shutdown_requested)
{
wfp_client_service(client, SERVICE_TIMEOUT);
}
wfp_client_dispose(client);
wfp_static_filesystem_dispose(fs);
wfp_client_config_dispose(config);
}
if (args.show_help)
{
print_usage();
}
return result;
}

@ -1,10 +1,26 @@
////////////////////////////////////////////////////////////////////////////////
/// \file adapter/api.h
/// \brief API define for webfuse adapter.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_ADAPTER_API_H
#define WF_ADAPTER_API_H
//------------------------------------------------------------------------------
/// \def WF_API
/// \brief Marks public symbols of libwebfuse_adapter.
//------------------------------------------------------------------------------
#ifndef WF_API
#define WF_API
#endif
//------------------------------------------------------------------------------
/// \def WF_EXPORT
/// \brief Marks exported symbols as visible.
///
/// Set WF_API to WF_EXPORT when building libwebfuse_adapter.so to export
/// public symbols.
//------------------------------------------------------------------------------
#ifndef WF_EXPORT
#ifdef __GNUC__
#define WF_EXPORT __attribute__ ((visibility ("default")))

@ -1,3 +1,8 @@
////////////////////////////////////////////////////////////////////////////////
/// \file adapter/authenticate.h
/// \brief Authenticate function.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_ADAPTER_AUTHENTICATE_H
#define WF_ADAPTER_AUTHENTICATE_H
@ -12,6 +17,19 @@ extern "C"
struct wf_credentials;
//------------------------------------------------------------------------------
/// \brief Authentication function type.
///
/// Functions of this type are used to authenticate a user by some provided
/// credentials.
///
/// \param credentials credentials to authenticate the user
/// \param user_data context of the authentication function
/// \return true, if authentication was successful, false otherwise
///
/// \see wf_server_config_add_authenticator
/// \see wf_server_protocol_add_authenticator
//------------------------------------------------------------------------------
typedef bool wf_authenticate_fn(
struct wf_credentials * credentials,
void * user_data);

@ -1,3 +1,8 @@
////////////////////////////////////////////////////////////////////////////////
/// \file adapter/credentials.h
/// \brief Credentials used for user authentication.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_ADAPTER_CREDENTIALS_H
#define WF_ADAPTER_CREDENTIALS_H
@ -8,11 +13,54 @@ extern "C"
{
#endif
//------------------------------------------------------------------------------
/// \struct wf_credentials
/// \brief Credentials used for user authentication.
///
/// Credentials are used during authentication to authenticate a user.
/// In order to support multiple types of credentials, e.g. username + password,
/// certifactes and / or authentication tokens, credentials are modelled as
/// opaque type with some access functions.
///
/// \see wf_authenticate_fn
/// \see wf_credentials_type
/// \see wf_credentials_get
//------------------------------------------------------------------------------
struct wf_credentials;
//------------------------------------------------------------------------------
/// \brief Returns the type of the credentials object.
///
/// The type of the credentials objects defines, which keys are available
/// for a given instance.
///
/// \note When an authenticate function is called, the credentials type
/// matches the type provided during _add_authenticator function call.
/// Therefore, it is not necessary to check credentials type within
/// the authenticate function.
///
/// \note Within webfuse protocol documentation, only one type of credentials
/// is described byte now: username
///
/// \param credentials Pointer to credentials object
/// \return type of the credentials object
///
/// \see wf_server_config_add_authenticator
/// \see wf_server_protocol_add_authenticator
/// \see wf_authenticate_fn
//------------------------------------------------------------------------------
extern WF_API char const * wf_credentials_type(
struct wf_credentials const * credentials);
//------------------------------------------------------------------------------
/// \brief Return the value of a credentials item identified by the provided
/// key.
///
/// \param credentials Pointer to credentials object.
/// \param key String to identify the item.
/// \return value of credentials item or null, if there is no item with that
/// key
//------------------------------------------------------------------------------
extern WF_API char const * wf_credentials_get(
struct wf_credentials const * credentials,
char const * key);

@ -0,0 +1,84 @@
////////////////////////////////////////////////////////////////////////////////
/// \file adapter/mountpoint.h
/// \brief Mointpoint.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_ADAPTER_MOUNTPOINT_H
#define WF_ADAPTER_MOUNTPOINT_H
#include <webfuse/adapter/api.h>
#ifdef __cplusplus
extern "C"
{
#endif
//------------------------------------------------------------------------------
/// \struct wf_mountpoint
/// \brief Mointpoint.
//------------------------------------------------------------------------------
struct wf_mountpoint;
//------------------------------------------------------------------------------
/// \brief Disposes the user defined context of a mountpoint.
///
/// \param user_data user defined context of the mointpoint.
///
/// \see wf_mountpoint_set_userdata
//------------------------------------------------------------------------------
typedef void
wf_mountpoint_userdata_dispose_fn(
void * user_data);
//------------------------------------------------------------------------------
/// \brief Creates a mountpoint.
///
/// \param path local path of the mounpoint
/// \return Newly created mountpoint.
//------------------------------------------------------------------------------
extern WF_API struct wf_mountpoint *
wf_mountpoint_create(
char const * path);
//------------------------------------------------------------------------------
/// \brief Disposes a mountpoint.
///
/// \param mountpoint pointer to the mountpoint
//------------------------------------------------------------------------------
extern WF_API void
wf_mountpoint_dispose(
struct wf_mountpoint * mountpoint);
//------------------------------------------------------------------------------
/// \brief Returns the local path of the mountpoint.
///
/// \param mountpoint pointer to the mountpoint
/// \return local path of the mountpoint
//------------------------------------------------------------------------------
extern WF_API char const *
wf_mountpoint_get_path(
struct wf_mountpoint const * mountpoint);
//------------------------------------------------------------------------------
/// \brief Sets user data of the mointpoint.
///
/// \note This function is intended for custom mountpoint factories to
/// annotate mountpoints with a user specified context.
///
/// \param mounpoint pointer to the mountpoint
/// \param user_data user data
/// \param dispose pointer to dipose function of user data or NULL,
/// if there is no need to dispose user data
//------------------------------------------------------------------------------
extern WF_API void
wf_mountpoint_set_userdata(
struct wf_mountpoint * mointpoint,
void * user_data,
wf_mountpoint_userdata_dispose_fn * dispose);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,39 @@
////////////////////////////////////////////////////////////////////////////////
/// \file adapter/mountpoint_factory.h
/// \brief Defines a factory function to create mointpoints.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_ADAPTER_MOUNTPOINT_FACTORY_H
#define WF_ADAPTER_MOUNTPOINT_FACTORY_H
#include <webfuse/adapter/api.h>
#ifdef __cplusplus
extern "C"
{
#endif
struct wf_mountpoint;
//------------------------------------------------------------------------------
/// \brief Factory function to create mountpoints.
///
/// \param filesystem name the filesystem
/// \param user_data context of the factory
/// \return newly created mountpoint or NULL, on error
///
/// \see wf_server_config_set_mountpoint_factory
/// \see wf_server_protocol_create
//------------------------------------------------------------------------------
typedef struct wf_mountpoint *
wf_create_mountpoint_fn(
char const * filesystem,
void * user_data);
#ifdef __cplusplus
}
#endif
#endif

@ -1,3 +1,8 @@
////////////////////////////////////////////////////////////////////////////////
/// \file adapter/server.h
/// \brief Adapter server.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_ADAPTER_SERVER_H
#define WF_ADAPTER_SERVER_H
@ -8,18 +13,57 @@ extern "C"
{
#endif
//------------------------------------------------------------------------------
/// \struct wf_server
/// \brief Webfuse adapter server object.
//------------------------------------------------------------------------------
struct wf_server;
struct wf_server_config;
//------------------------------------------------------------------------------
/// \brief Creates a new server.
///
/// \param config pointer to server configuration.
/// \return newly created server or NULL in case of an error
//------------------------------------------------------------------------------
extern WF_API struct wf_server * wf_server_create(
struct wf_server_config * config);
//------------------------------------------------------------------------------
/// \brief Disposes a server.
///
/// \note server configuration is not managed by server.
///
/// \param server pointer to server
//------------------------------------------------------------------------------
extern WF_API void wf_server_dispose(
struct wf_server * server);
//------------------------------------------------------------------------------
/// \brief Triggers the server.
///
/// This function must be invoked in a loop while the server is running. It
/// makes the server wait for the next event and processes it.
///
/// \param server pointer to server
///
/// \see wf_server_interrupt
//------------------------------------------------------------------------------
extern WF_API void wf_server_service(
struct wf_server * server,
int timeout_ms);
struct wf_server * server);
//------------------------------------------------------------------------------
/// \brief Interrupts wf_server_service
///
/// This function can be used from another thread.
///
/// \param server pointer to server
///
/// \see wf_server_service
//------------------------------------------------------------------------------
extern WF_API void wf_server_interrupt(
struct wf_server * server);
#ifdef __cplusplus
}

@ -1,52 +1,150 @@
////////////////////////////////////////////////////////////////////////////////
/// \file adapter/server_config.h
/// \brief Server configuration.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_ADAPTER_SERVER_CONFIG_H
#define WF_ADAPTER_SERVER_CONFIG_H
#include "webfuse/adapter/api.h"
#include "webfuse/adapter/authenticate.h"
#include "webfuse/adapter/mountpoint_factory.h"
#ifdef __cplusplus
extern "C"
{
#endif
//------------------------------------------------------------------------------
/// \struct wf_server_config
/// \brief Holds configuration of webfuse adapter server.
//------------------------------------------------------------------------------
struct wf_server_config;
//------------------------------------------------------------------------------
/// \brief Creates a new server configuration.
///
/// \return newly created server configuration
//------------------------------------------------------------------------------
extern WF_API struct wf_server_config * wf_server_config_create(void);
//------------------------------------------------------------------------------
/// \brief Disposes a server configuration.
///
/// \note Contexts of mounpoint factory and added authenticators are not
/// disposed by default.
///
/// \param config pointer of configuration object
///
/// \see wf_server_config_set_mountpoint_factory
/// \see wf_server_config_add_authenticator
//------------------------------------------------------------------------------
extern WF_API void wf_server_config_dispose(
struct wf_server_config * config);
extern WF_API void wf_server_config_set_mountpoint(
//------------------------------------------------------------------------------
/// \brief Sets the mountpoint factory of the configuration.
///
/// The mountpoint factory is called when a authenticated user adds a
/// filesystem.
///
/// \note The user is responsible to manage the lifetime of the mountpoint
/// factory.
///
/// \note A valid configuration needs either a mountpoint or a mounpoint
/// factory.
///
/// \param config pointer of configuration object
/// \param create_mountpoint factory function to create a mountpoint
/// \param user_data context of mountpoint factory
//------------------------------------------------------------------------------
extern WF_API void wf_server_config_set_mountpoint_factory(
struct wf_server_config * config,
char const * mount_point);
wf_create_mountpoint_fn * create_mountpoint,
void * user_data);
//------------------------------------------------------------------------------
/// \brief Sets the path of HTTP servers root context.
///
/// Webfuse adapter server is capable of serving static HTTP context. This
/// function is used to specify the path of HTTP servers root context.
/// If not specified, no HTTP content is served.
///
/// \param config pointer of configuration object
/// \param document_root path to static HTTP content
//------------------------------------------------------------------------------
extern WF_API void wf_server_config_set_documentroot(
struct wf_server_config * config,
char const * document_root);
//------------------------------------------------------------------------------
/// \brief Sets the path to the servers private key.
///
/// \note To enable TLS, private key and server certificate must be set.
/// Otherwise, only plain HTTP is supported.
///
/// \param config pointer of configuration object
/// \param key_path path to servers private key (pem file)
//------------------------------------------------------------------------------
extern WF_API void wf_server_config_set_keypath(
struct wf_server_config * config,
char const * key_path);
//------------------------------------------------------------------------------
/// \brief Sets path to servers certificate.
///
/// \note To enable TLS, private key and server certificate must be set.
/// Otherwise, only plain HTTP is supported.
///
/// \param config pointer of configuration object
/// \param cert_path path to servers certificate (pem file)
//------------------------------------------------------------------------------
extern WF_API void wf_server_config_set_certpath(
struct wf_server_config * config,
char const * cert_path);
//------------------------------------------------------------------------------
/// \brief Sets the virtual hostname of the websockets server.
///
/// \param config pointer of configuration object
/// \param vhost_name virtual hostname of the websockets server
//------------------------------------------------------------------------------
extern WF_API void wf_server_config_set_vhostname(
struct wf_server_config * config,
char const * vhost_name);
//------------------------------------------------------------------------------
/// \brief Sets the port number of the websockets server.
///
/// \param config pointer of configuration object
/// \param port port number of the websockets server
//------------------------------------------------------------------------------
extern WF_API void wf_server_config_set_port(
struct wf_server_config * config,
int port);
//------------------------------------------------------------------------------
/// \brief Adds an authenticator.
///
/// Authenticators are used to authenticate users by some provided credentials.
/// Multiple providers can be specified to support different types of
/// credentials.
///
/// \note Adding multiple providers for the same credentials type results
/// in undefined behavior.
///
/// \note The user is responsible to manage the lifetime of user data.
///
/// \param config pointer to configuration object
/// \param type type of the credentials the authenticator supports
/// \param authenticate function called to authenticate a user
/// \param user_data context of authenticate function
//------------------------------------------------------------------------------
extern WF_API void wf_server_config_add_authenticator(
struct wf_server_config * config,
char const * type,
wf_authenticate_fn * authenticate,
void * user_data
);
void * user_data);
#ifdef __cplusplus
}

@ -1,27 +1,89 @@
////////////////////////////////////////////////////////////////////////////////
/// \file adapter/server_protocol.h
/// \brief Provides low level access to libwebsockets protocol.
///
/// By default, libwebfuse encapsulates libwebsockets protocol by \ref
/// wf_server. But sometimes it might come in handy to have access to
/// libwebsockets protocol. This allows to integrate libwebfuse in existing
/// libwebsockets applications.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_ADAPTER_SERVER_PROTOCOL_H
#define WF_ADAPTER_SERVER_PROTOCOL_H
#include <webfuse/adapter/api.h>
#include <webfuse/adapter/authenticate.h>
#include <webfuse/adapter/mountpoint_factory.h>
#ifdef __cplusplus
extern "C"
{
#endif
//------------------------------------------------------------------------------
/// \struct wf_server_protocol
/// \brief Opaque webfuse server protocol.
//------------------------------------------------------------------------------
struct wf_server_protocol;
//------------------------------------------------------------------------------
/// \struct lws_protocols
/// \brief Forward declaration of libwebsockets protocols structure.
//------------------------------------------------------------------------------
struct lws_protocols;
//------------------------------------------------------------------------------
/// \brief Creates a new protocol by a mountpoint factory.
///
/// \note This function might be renamed in future releases.
///
/// \note The user is responsible to manage the lifetime of mountpoint factory.
///
/// \param create_mountpoint factory function to create mountpoints
/// \param create_mountpoint_context context of mountpoint factory
//------------------------------------------------------------------------------
extern WF_API struct wf_server_protocol * wf_server_protocol_create(
char * mount_point);
wf_create_mountpoint_fn * create_mountpoint,
void * create_mountpoint_context);
//------------------------------------------------------------------------------
/// \brief Disposes a protocol.
///
/// \note Contexts of mountpoint factory and added authenticators are not
/// managed by dispose.
///
/// \param protocol pointer to protocol
//------------------------------------------------------------------------------
extern WF_API void wf_server_protocol_dispose(
struct wf_server_protocol * protocol);
//------------------------------------------------------------------------------
/// \brief Intializes a libwebsockets protocol structure.
///
/// \param protocol pointer to protocol
/// \param lws_protocols pointer to libwebsockets protocol structure
//------------------------------------------------------------------------------
extern WF_API void wf_server_protocol_init_lws(
struct wf_server_protocol * protocol,
struct lws_protocols * lws_protocol);
//------------------------------------------------------------------------------
/// \brief Adds an authenticator.
///
/// Authenticators are used to authenticate users by some provided credentials.
/// Multiple providers can be specified to support different types of
/// credentials.
///
/// \note Adding multiple providers for the same credentials type results
/// in undefined behavior.
///
/// \note The user is responsible to manage the lifetime of user data.
///
/// \param protocol pointer to protocol
/// \param type type of the credentials the authenticator supports
/// \param authenticate function called to authenticate a user
/// \param user_data context of authenticate function
//------------------------------------------------------------------------------
extern WF_API void wf_server_protocol_add_authenticator(
struct wf_server_protocol * protocol,
char const * type,

@ -0,0 +1,21 @@
////////////////////////////////////////////////////////////////////////////////
/// \file protocol_names.h
/// \brief Names of websocket protocol.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_PROTOCOL_NAMES_H
#define WF_PROTOCOL_NAMES_H
//------------------------------------------------------------------------------
/// \def WF_PROTOCOL_NAME_ADAPTER_SERVER
/// \brief Name of the websocket protocol an adapter server is running.
//------------------------------------------------------------------------------
#define WF_PROTOCOL_NAME_ADAPTER_SERVER ("webfuse-adapter-server")
//------------------------------------------------------------------------------
/// \def WF_PROTOCOL_NAME_PROVIDER_CLIENT
/// \brief Name of the websocket protocol an provider client is running.
//------------------------------------------------------------------------------
#define WF_PROTOCOL_NAME_PROVIDER_CLIENT ("webfuse-provider-client")
#endif

@ -1,17 +1,23 @@
////////////////////////////////////////////////////////////////////////////////
/// \file status.h
/// \brief Generic status code.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_STATUS_H
#define WF_STATUS_H
#define WF_GOOD 0
#define WF_BAD 1
#define WF_GOOD 0 ///< Positive status code.
#define WF_BAD 1 ///< Generic negative status code.
#define WF_BAD_NOTIMPLEMENTED 2
#define WF_BAD_TIMEOUT 3
#define WF_BAD_BUSY 4
#define WF_BAD_FORMAT 5
#define WF_BAD_NOTIMPLEMENTED 2 ///< The called function is not implemented (yet).
#define WF_BAD_TIMEOUT 3 ///< A timeout occured.
#define WF_BAD_BUSY 4 ///< Resource is busy, try again later.
#define WF_BAD_FORMAT 5 ///< Invalid format.
#define WF_BAD_NOENTRY 101
#define WF_BAD_ACCESS_DENIED 102
#define WF_BAD_NOENTRY 101 ///< Entry not found.
#define WF_BAD_ACCESS_DENIED 102 ///< Access is denied.
/// Status code.
typedef int wf_status;
#endif

@ -1,10 +1,26 @@
////////////////////////////////////////////////////////////////////////////////
/// \file provider/api.h
/// \brief API define for webfuse provider.
////////////////////////////////////////////////////////////////////////////////
#ifndef WFP_PROVIDER_API_H
#define WFP_PROVIDER_API_H
//------------------------------------------------------------------------------
/// \def WFP_API
/// \brief Marks public symbols of libwebfuse_provider.
//------------------------------------------------------------------------------
#ifndef WFP_API
#define WFP_API
#endif
//------------------------------------------------------------------------------
/// \def WFP_EXPORT
/// \brief Marks exported symbols as visible.
///
/// Set WFP_API to WFP_EXPORT when building libwebfuse_provider.so to export
/// public symbols.
//------------------------------------------------------------------------------
#ifndef WFP_EXPORT
#ifdef __GNUC__
#define WFP_EXPORT __attribute__ ((visibility ("default")))

@ -1,3 +1,8 @@
////////////////////////////////////////////////////////////////////////////////
/// \file provider/client.h
/// \brief Webfuse provider client.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_PROVIDER_CLIENT_H
#define WF_PROVIDER_CLIENT_H
@ -8,25 +13,89 @@ extern "C"
{
#endif
//------------------------------------------------------------------------------
/// \struct wfp_client
/// \brief Webfuse provider client.
//------------------------------------------------------------------------------
struct wfp_client;
struct wfp_client_config;
//------------------------------------------------------------------------------
/// \brief Creates a webfuse provider client.
///
/// \note Client configuration is not managed by the client.
///
/// \param config pointer to client configuration.
/// \return newly created client or NULL in case of an error.
//------------------------------------------------------------------------------
extern WFP_API struct wfp_client * wfp_client_create(
struct wfp_client_config * config);
//------------------------------------------------------------------------------
/// \brief Connects the client to a remote webfuse adapter server.
///
/// \note This call starts to establish a connection. A callback is invoked,
/// when the connection is estanlished.
///
/// \param client pointer to client
/// \param url URL of remote webfuse adapter server
///
/// \see wfp_connected_fn
/// \see wfp_client_config_set_onconnected
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_connect(
struct wfp_client * client,
char const * url);
//------------------------------------------------------------------------------
/// \brief Disconnects a connected client.
///
/// \note This call starts to disconnect the connection. A callback is invoked
/// when conntection is disconnected.
///
/// \param client pointer to client
///
/// \see wfp_disconnected_fn
/// \see wfp_client_config_set_ondisconnected
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_disconnect(
struct wfp_client * client);
//------------------------------------------------------------------------------
/// \brief Disposes a client.
///
/// \note Client configuration is not managed by client.
///
/// \param client pointer to client
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_dispose(
struct wfp_client * client);
//------------------------------------------------------------------------------
/// \brief Triggers the client.
///
/// This function must be invoked in a loop while the client is running. It
/// makes the server wait for the next event and processes it.
///
/// \param client pointer to client
///
/// \see wfp_client_interrupt
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_service(
struct wfp_client * client,
int timeout_ms);
struct wfp_client * client);
//------------------------------------------------------------------------------
/// \brief interrupt wfp_client_service
///
/// This function can be called from another thread.
///
/// \param client pointer to client
///
/// \see wfp_client_service
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_interrupt(
struct wfp_client * client);
#ifdef __cplusplus
}

@ -1,3 +1,8 @@
////////////////////////////////////////////////////////////////////////////////
/// \file provider/client_config.h
/// \brief Client configuration of webfuse provider.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_PROVIDER_CLIENT_CONFIG_H
#define WF_PROVIDER_CLIENT_CONFIG_H
@ -9,77 +14,224 @@
#include <webfuse/provider/operation/open.h>
#include <webfuse/provider/operation/close.h>
#include <webfuse/provider/operation/read.h>
#include <webfuse/provider/credentials.h>
#ifdef __cplusplus
extern "C"
{
#endif
//------------------------------------------------------------------------------
/// \struct wfp_client_config
/// \brief Provider client configuration object.
///
/// Holds configuration of webfuse provider client.
//------------------------------------------------------------------------------
struct wfp_client_config;
//------------------------------------------------------------------------------
/// \brief Callback to signal when the client's connection is established.
///
/// \param user_data user defined context
//------------------------------------------------------------------------------
typedef void wfp_connected_fn(
void * user_data);
//------------------------------------------------------------------------------
/// \brief Callback to signal when a client's connection is disconnected.
///
/// \param user_data user defined context
//------------------------------------------------------------------------------
typedef void wfp_disconnected_fn(
void * user_data);
typedef void wfp_ontimer_fn(
void * user_data);
//------------------------------------------------------------------------------
/// \brief Creates a new client configuration.
///
/// \return newly created client configuration
//------------------------------------------------------------------------------
extern WFP_API struct wfp_client_config * wfp_client_config_create(void);
//------------------------------------------------------------------------------
/// \brief Disposes a client configuration.
///
/// \note The user defined context is not managed by the client configuration.
///
/// \param config pointer to client configuration
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_dispose(
struct wfp_client_config * config);
//------------------------------------------------------------------------------
/// \brief Sets a user defined context.
///
/// \note The user is responsible to manage the lifetime of user data.
///
/// \param config pointer to client configuration
/// \param user_data user defined context
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_set_userdata(
struct wfp_client_config * config,
void * user_data);
//------------------------------------------------------------------------------
/// \brief Sets the path to clients private key.
///
/// \note To enable TLS both, private key and certificate, must be specified.
/// Otherwise, TLS is not used.
///
/// \param config pointer to client configuration
/// \param key_path path of clients private key (pem file)
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_set_keypath(
struct wfp_client_config * config,
char const * key_path);
//------------------------------------------------------------------------------
/// \brief Sets the path of clients certificate.
///
/// \note To enable TLS both, private key and certificate, must be specified.
/// Otherwise, TLS is not used.
///
/// \param config pointer to client configuration
/// \param cert_path path of the clients certificate (pem file)
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_set_certpath(
struct wfp_client_config * config,
char const * cert_path);
//------------------------------------------------------------------------------
/// \brief Sets the path of ca file to verify servers.
///
/// \note To enable TLS both, private key and certificate, must be specified.
/// Otherwise, TLS is not used.
///
/// \param config pointer to client configuration
/// \param ca_filepath path of the ca file (pem file)
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_set_ca_filepath(
struct wfp_client_config * config,
char const * ca_filepath);
//------------------------------------------------------------------------------
/// \brief Sets the onconnected handler.
///
/// The handler is invoked, when the client's conntection is established.
///
/// \param config pointer to client configuration
/// \param handler pointer to handler
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_set_onconnected(
struct wfp_client_config * config,
wfp_connected_fn * handler);
//------------------------------------------------------------------------------
/// \brief Sets ondisconnected handler
///
/// The handler is invoked, when the client's conntection is lost.
///
/// \param config pointer to client configuration
/// \param handler pointer to handler
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_set_ondisconnected(
struct wfp_client_config * config,
wfp_disconnected_fn * handler);
extern WFP_API void wfp_client_config_set_ontimer(
struct wfp_client_config * config,
wfp_ontimer_fn * handler);
//------------------------------------------------------------------------------
/// \brief Sets onlookup handler.
///
/// The handler is invoked, when the identifier of a file is requested.
///
/// \param config pointer to client configuration
/// \param handler pointer to handler
///
/// \see wfp_lookup_fn
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_set_onlookup(
struct wfp_client_config * config,
wfp_lookup_fn * handler);
//------------------------------------------------------------------------------
/// \brief Sets ongetattr handler.
///
/// The handler is invoked, when attributes of a file are requested.
///
/// \param config pointer to client configuration
/// \param handler pointer to handler
///
/// \see wfp_getattr_fn
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_set_ongetattr(
struct wfp_client_config * config,
wfp_getattr_fn * handler);
//------------------------------------------------------------------------------
/// \brief Sets onreaddir handler.
///
/// The handler is invoked, when the contents of directory are requested-
///
/// \param config pointer to client configuration
/// \param handler pointer to handler
///
/// \see wfp_readdir_fn
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_set_onreaddir(
struct wfp_client_config * config,
wfp_readdir_fn * handler);
//------------------------------------------------------------------------------
/// \brief Sets onopen handler.
///
/// The handler is invoked, whe a file should be opened.
///
/// \param config pointer to client configuration
/// \param handler pointer to handler
///
/// \see wfp_open_fn
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_set_onopen(
struct wfp_client_config * config,
wfp_open_fn * handler);
//------------------------------------------------------------------------------
/// \brief Sets onclose handler.
///
/// The handler is invoked, when a file is closed.
///
/// \param config pointer to client configuration
/// \param handler pointer to handler
///
/// \see wfp_close_fn
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_set_onclose(
struct wfp_client_config * config,
wfp_close_fn * handler);
//------------------------------------------------------------------------------
/// \brief Sets onread handler.
///
/// The handler is invoked, when a files content is requested.
///
/// \param config pointer to client configuration
/// \param handler pointer to handler
///
/// \see wfp_read_fn
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_set_onread(
struct wfp_client_config * config,
wfp_read_fn * handler);
//------------------------------------------------------------------------------
/// \brief Enabled authentication.
///
/// \param config pointer to client configuration
/// \param get_credentials pointer to function providing credentials when
// needed.
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_config_enable_authentication(
struct wfp_client_config * config,
wfp_get_credentials_fn * get_credentials);
#ifdef __cplusplus
}
#endif

@ -1,3 +1,13 @@
////////////////////////////////////////////////////////////////////////////////
/// \file provider/client_protocol.h
/// \brief Provides low level access to libwebsockets protocol.
///
/// By default, libwebfuse encapsulates libwebsockets protocol by \ref
/// wfp_client. But sometimes it might come in handy to have access to
/// libwebsockets protocol. This allows to integrate libwebfuse in existing
/// libwebsockets applications.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_PROVIDER_CLIENT_PROTOCOL_H
#define WF_PROVIDER_CLIENT_PROTOCOL_H
@ -8,21 +18,96 @@ extern "C"
{
#endif
//------------------------------------------------------------------------------
/// \struct wfp_client_protocol
/// \brief Opaque webfuse client protocol..
//------------------------------------------------------------------------------
struct wfp_client_protocol;
struct wfp_provider;
//------------------------------------------------------------------------------
/// \struct lws_protocols
/// \brief Forward declaration of libwebsockets protocols structure.
//------------------------------------------------------------------------------
struct lws_protocols;
//------------------------------------------------------------------------------
/// \struct lws_context
/// \brief Forward declaration of libwebsockets context structure.
//------------------------------------------------------------------------------
struct lws_context;
//------------------------------------------------------------------------------
/// \struct wfp_client_config
/// \copydoc wfp_client_config
//------------------------------------------------------------------------------
struct wfp_client_config;
//------------------------------------------------------------------------------
/// \brief Creates a new webfuse provider client protocol.
///
/// \note The user is responsible to manage lifetime of \arg config.
///
/// \note TLS configuration is ignored, since TLS is managed by libwebsockets.
///
/// \param config pointer to client config
/// \return newly created protocol
//------------------------------------------------------------------------------
extern WFP_API struct wfp_client_protocol * wfp_client_protocol_create(
struct wfp_provider const * provider,
void * user_data);
struct wfp_client_config const * config);
//------------------------------------------------------------------------------
/// \brief Disposes a protocol.
///
/// \note The user defined context is not managed by the protocol.
///
/// \param protocol pointer to protocol.
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_protocol_dispose(
struct wfp_client_protocol * protocol);
//------------------------------------------------------------------------------
/// \brief Initialized libwebsockets protocol structure.
///
/// \param protocol pointer to protocol
/// \param lws_protocol pointer to libwebsockets protocol structure.
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_protocol_init_lws(
struct wfp_client_protocol * protocol,
struct lws_protocols * lws_protocol);
//------------------------------------------------------------------------------
/// \brief Connects the protocol to a remote webfuse adapter server.
///
/// \note This call starts to establish a connection. A callback is invoked,
/// when the connection is estanlished.
///
/// \param protocol pointer to protocol
/// \param context lws context
/// \param url URL of remote webfuse adapter server
///
/// \see wfp_connected_fn
/// \see wfp_client_config_set_onconnected
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_protocol_connect(
struct wfp_client_protocol * protocol,
struct lws_context * context,
char const * url);
//------------------------------------------------------------------------------
/// \brief Disconnects the protocol from a remote webfuse adapter server.
///
/// \note This call starts to disconnect. A callback is invoked,
/// when the connection is estanlished.
///
/// \param protocol pointer to protocol
///
/// \see wfp_connected_fn
/// \see wfp_client_config_set_ondisconnected
//------------------------------------------------------------------------------
extern WFP_API void wfp_client_protocol_disconnect(
struct wfp_client_protocol * protocol);
#ifdef __cplusplus
}
#endif

@ -0,0 +1,30 @@
#ifndef WF_PROVIDER_CREDENTIALS_H
#define WF_PROVIDER_CREDENTIALS_H
#include <webfuse/provider/api.h>
#ifdef __cplusplus
extern "C"
{
#endif
struct wfp_credentials;
typedef void wfp_get_credentials_fn(
struct wfp_credentials * credentials,
void * user_data);
extern WFP_API void wfp_credentials_set_type(
struct wfp_credentials * credentials,
char const * type);
extern WFP_API void wfp_credentials_add(
struct wfp_credentials * credentials,
char const * key,
char const * value);
#ifdef __cplusplus
}
#endif
#endif

@ -1,3 +1,8 @@
////////////////////////////////////////////////////////////////////////////////
/// \file provider/dirbuffer.h
/// \brief Buffer used for directory listing.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_PROVIDER_DIRBUFFER_H
#define WF_PROVIDER_DIRBUFFER_H
@ -12,13 +17,36 @@ extern "C"
{
#endif
//------------------------------------------------------------------------------
/// \struct wfp_dirbuffer
/// \brief Buffer used for directory listing.
///
/// \see wfp_respond_readdir
//------------------------------------------------------------------------------
struct wfp_dirbuffer;
//------------------------------------------------------------------------------
/// \brief Creates a new dir buffer.
///
/// \return newly created dir buffer.
//------------------------------------------------------------------------------
extern WFP_API struct wfp_dirbuffer * wfp_dirbuffer_create(void);
//------------------------------------------------------------------------------
/// \brief Disposes a dir buffer.
///
/// \param buffer pointer to dir buffer
//------------------------------------------------------------------------------
extern WFP_API void wfp_dirbuffer_dispose(
struct wfp_dirbuffer * buffer);
//------------------------------------------------------------------------------
/// \brief Adds an entry to dir buffer.
///
/// \param buffer pointer to dir buffer
/// \param name name of the entry (file or directory)
/// \param inode inode of the entry
//------------------------------------------------------------------------------
extern WFP_API void wfp_dirbuffer_add(
struct wfp_dirbuffer * buffer,
char const * name,

@ -1,3 +1,8 @@
////////////////////////////////////////////////////////////////////////////////
/// \file provider/operation/close.h
/// \brief Provider's close callback.
////////////////////////////////////////////////////////////////////////////////
#ifndef WFP_OPERATION_CLOSE_H
#define WFP_OPERATION_CLOSE_H
@ -18,6 +23,16 @@ extern "C"
{
#endif
//------------------------------------------------------------------------------
/// \brief Callback invoked when a file is invoked.
///
/// This function does not respond.
///
/// \param inode inode of file to close
/// \param handle handle of file to close
/// \param flags file close flags
/// \param user_data user defined context
//------------------------------------------------------------------------------
typedef void wfp_close_fn(
ino_t inode,
uint32_t handle,

@ -1,3 +1,8 @@
////////////////////////////////////////////////////////////////////////////////
/// \file provider/operation/error.h
/// \brief Respond with error code.
////////////////////////////////////////////////////////////////////////////////
#ifndef WFP_OPERATION_ERROR_H
#define WFP_OPERATION_ERROR_H
@ -11,6 +16,15 @@ extern "C"
struct wfp_request;
//------------------------------------------------------------------------------
/// \brief Respond to a request with an error.
///
/// A client's callback must respond with exactly one responde, either with a
/// valid reponse regarding to the concrete request or with an error response.
///
/// \param request pointer to request
/// \param status error code
//------------------------------------------------------------------------------
extern WFP_API void wfp_respond_error(
struct wfp_request * request,
wf_status status);

@ -1,3 +1,8 @@
////////////////////////////////////////////////////////////////////////////////
/// \file provider/operation/getattr.h
/// \brief Get file attributes.
////////////////////////////////////////////////////////////////////////////////
#ifndef WFP_OPERATION_GETATTR_H
#define WFP_OPERATION_GETATTR_H
@ -14,11 +19,30 @@ extern "C"
struct wfp_request;
//------------------------------------------------------------------------------
/// \brief Get file attributes.
///
/// \note After this function is called, exactly one response must be sent,
/// either via \ref wfp_respond_getattr or via \ref wfp_respond_error.
///
/// \param request pointer to request
/// \param inode inode of file to get attributes
/// \param user_data user defined context
///
/// \see wfp_respond_getattr
/// \see wfp_respond_error
//------------------------------------------------------------------------------
typedef void wfp_getattr_fn(
struct wfp_request * request,
ino_t inode,
void * user_data);
//------------------------------------------------------------------------------
/// \brief Respond to a get attributes request.
///
/// \param request pointer to request
/// \param stat file attributes
//------------------------------------------------------------------------------
extern WFP_API void wfp_respond_getattr(
struct wfp_request * request,
struct stat const * stat);

@ -1,3 +1,8 @@
////////////////////////////////////////////////////////////////////////////////
/// \file provider/operation/lookup.h
/// \brief Lookup file.
////////////////////////////////////////////////////////////////////////////////
#ifndef WFP_OPERATION_LOOKUP_H
#define WFP_OPERATION_LOOKUP_H
@ -14,12 +19,32 @@ extern "C"
struct wfp_request;
//------------------------------------------------------------------------------
/// \brief Lookup a file or directory.
///
/// \note After this function is called, exactly one response must be sent,
/// either via \ref wfp_respond_lookup or via \ref wfp_respond_error.
///
/// \param request pointer to request
/// \param parent inode of parent
/// \param name name of the filesystem object to lookup
/// \param user_data pointer to user defined context
///
/// \see wfp_respond_lookup
/// \see wfp_respond_error
//------------------------------------------------------------------------------
typedef void wfp_lookup_fn(
struct wfp_request * request,
ino_t parent,
char const * name,
void * user_data);
//------------------------------------------------------------------------------
/// \brief Respond to lookup request.
///
/// \param request pointer to request
/// \param stat attributes of filesystem object
//------------------------------------------------------------------------------
extern WFP_API void wfp_respond_lookup(
struct wfp_request * request,
struct stat const * stat);

@ -1,3 +1,8 @@
////////////////////////////////////////////////////////////////////////////////
/// \file provider/operation/open.h
/// \brief Open a file.
////////////////////////////////////////////////////////////////////////////////
#ifndef WFP_OPERATION_OPEN_H
#define WFP_OPERATION_OPEN_H
@ -20,12 +25,32 @@ extern "C"
struct wfp_request;
//------------------------------------------------------------------------------
/// \brief Open a file.
///
/// \note After this function is called, exactly one response must be sent,
/// either via \ref wfp_respond_open or via \ref wfp_respond_error.
///
/// \param request pointer to request
/// \param inode inode of the file to open
/// \param flags file open flags
/// \param user_data user defined context
///
/// \see wfp_respond_open
/// \see wfp_respond_error
//------------------------------------------------------------------------------
typedef void wfp_open_fn(
struct wfp_request * request,
ino_t inode,
int flags,
void * user_data);
//------------------------------------------------------------------------------
/// \brief Respond to open file.
///
/// \param request pointer to request
/// \param handle handle of the opened file
//------------------------------------------------------------------------------
extern WFP_API void wfp_respond_open(
struct wfp_request * request,
uint32_t handle);

@ -1,3 +1,8 @@
////////////////////////////////////////////////////////////////////////////////
/// \file provider/operation/read.h
/// \brief Read contents of a file.
////////////////////////////////////////////////////////////////////////////////
#ifndef WFP_OPERATION_READ_H
#define WFP_OPERATION_READ_H
@ -23,6 +28,25 @@ extern "C"
struct wfp_request;
//------------------------------------------------------------------------------
/// \brief Requests content of a file.
///
/// On success, up to \arg length bytes should be returned via \ref
/// wfp_respond_read.
///
/// \note After this function is called, exactly one response must be sent,
/// either via \ref wfp_respond_read or via \ref wfp_respond_error.
///
/// \param request pointer to request
/// \param inode inode of the file to read
/// \param handle handle of the file to read (returned by open)
/// \param offset offset within the file where to start reading
/// \param length amount of bytes to read
/// \param user_data used defined context
///
/// \see wfp_respond_read
/// \see wfp_respond_error
//------------------------------------------------------------------------------
typedef void wfp_read_fn(
struct wfp_request * request,
ino_t inode,
@ -31,12 +55,20 @@ typedef void wfp_read_fn(
size_t length,
void * user_data);
//------------------------------------------------------------------------------
/// \brief Respond to read.
///
/// \note The user is responsible to manage lifetime of \arg data.
///
/// \param request pointer to request
/// \param data data read from file
/// \param length amount of bytes read
//------------------------------------------------------------------------------
extern WFP_API void wfp_respond_read(
struct wfp_request * request,
char const * data,
size_t length);
#ifdef __cplusplus
}
#endif

@ -1,3 +1,8 @@
////////////////////////////////////////////////////////////////////////////////
/// \file provider/operation/readdir.h
/// \brief List directory contents.
////////////////////////////////////////////////////////////////////////////////
#ifndef WFP_OPERATION_READDIR_H
#define WFP_OPERATION_READDIR_H
@ -15,11 +20,33 @@ extern "C"
struct wfp_dirbuffer;
struct wfp_request;
//------------------------------------------------------------------------------
/// \brief Requests the contents of a directory.
///
/// \note After this function is called, exactly one response must be sent,
/// either via \ref wfp_respond_readdir or via \ref wfp_respond_error.
///
/// \param request pointer to request
/// \param directory inode of directory to list
/// \param user_data user defined context
///
/// \see wfp_respond_readdir
/// \see wfp_respond_error
//------------------------------------------------------------------------------
typedef void wfp_readdir_fn(
struct wfp_request * request,
ino_t directory,
void * user_data);
//------------------------------------------------------------------------------
/// \brief Respond to list directory contents.
///
/// \note The user is responsible to manage dirbuffe, p.e. to dispose
/// it after this function is called.
///
/// \param request pointer to request
/// \param dirbuffer contains contents of directory
//------------------------------------------------------------------------------
extern WFP_API void wfp_respond_readdir(
struct wfp_request * request,
struct wfp_dirbuffer * dirbuffer);

@ -1,7 +1,13 @@
////////////////////////////////////////////////////////////////////////////////
/// \file webfuse_adapter.h
/// \brief Convenience header to include all functionality of libfuse_adapter.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_ADAPTER_H
#define WF_ADAPTER_H
#include <webfuse/core/status.h>
#include <webfuse/core/protocol_names.h>
#include <webfuse/adapter/api.h>
#include <webfuse/adapter/server.h>
@ -9,5 +15,6 @@
#include <webfuse/adapter/server_protocol.h>
#include <webfuse/adapter/authenticate.h>
#include <webfuse/adapter/credentials.h>
#include <webfuse/adapter/mountpoint.h>
#endif

@ -1,13 +1,20 @@
////////////////////////////////////////////////////////////////////////////////
/// \file webfuse_provider.h
/// \brief Convenience header to include all functionality of libfuse_provider.
////////////////////////////////////////////////////////////////////////////////
#ifndef WF_PROVIDER_H
#define WF_PROVIDER_H
#include <webfuse/core/status.h>
#include <webfuse/core/protocol_names.h>
#include <webfuse/provider/api.h>
#include <webfuse/provider/client.h>
#include <webfuse/provider/client_config.h>
#include <webfuse/provider/client_protocol.h>
#include <webfuse/provider/dirbuffer.h>
#include <webfuse/provider/credentials.h>
#include <webfuse/provider/operation/error.h>
#include <webfuse/provider/operation/lookup.h>
@ -17,6 +24,4 @@
#include <webfuse/provider/operation/close.h>
#include <webfuse/provider/operation/read.h>
#include <webfuse/provider/static_filesystem.h>
#endif

@ -1,172 +0,0 @@
#!/bin/bash
#
# Checks for dependencies and install them, if needed.
#
# A valid package description is defined as follows:
# local <package>_name=<name>
# local <package>_type=<type>
# local <package>_archive=<archive>
# local <package>_dir=<dir>
# local <package>_url=<url>
#
# <package> - symbolid id of package
# <name> - name of the package (used for pkg-config)
# <type> - type of project ("cmake" or "autotools")
# <archive> - archive file name
# <dir> - dir of package sources
# <url> - url of the project archive
#
# For examples, see below.
#
# Since <package>_ variables are not used directly, shellcheck will complain:
# shellcheck disable=SC2034
#######################################
# Installs a cmake package.
#
# Arguments:
# package - name of package
# Returns:
# 0 on success, otherwise failure
#######################################
function install_cmake_package() {
local package="$1"
local archive="${package}_archive"
local dir="${package}_dir"
local url="${package}_url"
wget -O "${!archive}" "${!url}" && \
tar -xf "${!archive}" && \
cd "${!dir}" && \
mkdir .build && \
cd .build && \
cmake .. && \
make && \
sudo make install && \
cd .. && \
cd ..
return "$?"
}
#######################################
# Installs a autotools package.
#
# Arguments:
# package - name of package
# Returns:
# 0 on success, otherwise failure
#######################################
function install_autotools_package() {
local package="$1"
local archive="${package}_archive"
local dir="${package}_dir"
local url="${package}_url"
wget -O "${!archive}" "${!url}" && \
tar -xf "${!archive}" && \
cd "${!dir}" && \
./makeconf.sh && \
./configure && \
make && \
sudo make install && \
cd ..
return "$?"
}
#######################################
# Checks, whether a package exists.
#
# Arguments:
# package_name - name of package
# Returns:
# 0 if package exists, otherwise failure
#######################################
function package_exists() {
local package_name="$1"
pkg-config --exists "${package_name}"
return "$?"
}
#######################################
# Installs a package, if it is not available.
#
# Arguments:
# package - name of package
# Returns:
# 0 if package exists, otherwise failure
#######################################
function install_if_needed() {
local package="$1"
local package_name="${package}_name"
local package_type="${package}_type"
local result=0
package_exists "${!package_name}"
if [[ "$?" -ne 0 ]]; then
"install_${!package_type}_package" "$package"
result="$?"
fi
return "${result}"
}
#######################################
# Main
#
# Arguments:
# None
# Returns:
# 0 on success, otherwise failure
#######################################
function main() {
rm -rf .deps
mkdir .deps
cd .deps
local packages=(fuse3 lws jansson gtest)
local fuse3_name=fuse3
local fuse3_type=autotools
local fuse3_archive=fuse-3.1.1.tar.gz
local fuse3_dir=libfuse-fuse-3.1.1
local fuse3_url=https://github.com/libfuse/libfuse/archive/fuse-3.1.1.tar.gz
local lws_name=libwebsockets
local lws_type=cmake
local lws_archive=libwebsockets-3.1.0.tar.gz
local lws_dir=libwebsockets-3.1.0
local lws_url=https://github.com/warmcat/libwebsockets/archive/v3.1.0.tar.gz
local jansson_name=jansson
local jansson_type=cmake
local jansson_archive=libjansson-2.12.tar.gz
local jansson_dir=jansson-2.12
local jansson_url=https://github.com/akheron/jansson/archive/v2.12.tar.gz
local gtest_name=gtest_main
local gtest_type=cmake
local gtest_archive=gtest-1.8.1.tar.gz
local gtest_dir=googletest-release-1.8.1
local gtest_url=https://github.com/google/googletest/archive/release-1.8.1.tar.gz
local result=0
local package=""
for package in "${packages[@]}" ; do
install_if_needed $package
result="$?"
if [[ "${result}" -ne 0 ]] ; then
cd ..
return "${result}"
fi
done
cd ..
return 0
}
main "$@"

@ -4,6 +4,9 @@
#include "webfuse/adapter/impl/server_protocol.h"
#include "webfuse/adapter/impl/server_config.h"
#include "webfuse/adapter/impl/credentials.h"
#include "webfuse/adapter/impl/mountpoint.h"
#include "webfuse/core/util.h"
// server
@ -20,18 +23,25 @@ void wf_server_dispose(
}
void wf_server_service(
struct wf_server * server,
int timeout_ms)
struct wf_server * server)
{
wf_impl_server_service(server);
}
void wf_server_interrupt(
struct wf_server * server)
{
wf_impl_server_service(server, timeout_ms);
wf_impl_server_interrupt(server);
}
// server protocol
struct wf_server_protocol * wf_server_protocol_create(
char * mount_point)
wf_create_mountpoint_fn * create_mountpoint,
void * create_mountpoint_context)
{
return wf_impl_server_protocol_create(mount_point);
return wf_impl_server_protocol_create(create_mountpoint, create_mountpoint_context);
}
void wf_server_protocol_dispose(
@ -69,11 +79,13 @@ void wf_server_config_dispose(
wf_impl_server_config_dispose(config);
}
void wf_server_config_set_mountpoint(
void wf_server_config_set_mountpoint_factory(
struct wf_server_config * config,
char const * mount_point)
wf_create_mountpoint_fn * create_mountpoint,
void * user_data)
{
wf_impl_server_config_set_mountpoint(config, mount_point);
wf_impl_server_config_set_mountpoint_factory(
config, create_mountpoint, user_data);
}
void wf_server_config_set_documentroot(
@ -134,3 +146,35 @@ char const * wf_credentials_get(
{
return wf_impl_credentials_get(credentials, key);
}
// mountpoint
struct wf_mountpoint *
wf_mountpoint_create(
char const * path)
{
return wf_impl_mountpoint_create(path);
}
void
wf_mountpoint_dispose(
struct wf_mountpoint * mountpoint)
{
wf_impl_mountpoint_dispose(mountpoint);
}
char const *
wf_mountpoint_get_path(
struct wf_mountpoint const * mountpoint)
{
return wf_impl_mountpoint_get_path(mountpoint);
}
void
wf_mountpoint_set_userdata(
struct wf_mountpoint * mountpoint,
void * user_data,
wf_mountpoint_userdata_dispose_fn * dispose)
{
wf_impl_mountpoint_set_userdata(mountpoint, user_data, dispose);
}

@ -11,13 +11,10 @@ struct wf_impl_authenticator * wf_impl_authenticator_create(
void * user_data)
{
struct wf_impl_authenticator * authenticator = malloc(sizeof(struct wf_impl_authenticator));
if (NULL != authenticator)
{
authenticator->type = strdup(type);
authenticator->authenticate = authenticate;
authenticator->user_data = user_data;
authenticator->next = NULL;
}
authenticator->type = strdup(type);
authenticator->authenticate = authenticate;
authenticator->user_data = user_data;
authenticator->next = NULL;
return authenticator;
}

@ -1,11 +1,17 @@
#include "webfuse/adapter/impl/filesystem.h"
#include "webfuse/adapter/impl/operations.h"
#include "webfuse/adapter/impl/operation/context.h"
#include "webfuse/adapter/impl/operation/open.h"
#include "webfuse/adapter/impl/operation/close.h"
#include "webfuse/adapter/impl/operation/read.h"
#include "webfuse/adapter/impl/operation/readdir.h"
#include "webfuse/adapter/impl/operation/getattr.h"
#include "webfuse/adapter/impl/operation/lookup.h"
#include "webfuse/adapter/impl/session.h"
#include "webfuse/adapter/impl/mountpoint.h"
#include "webfuse/core/string.h"
#include <libwebsockets.h>
#include <uuid/uuid.h>
#include <sys/stat.h>
#include <sys/types.h>
@ -27,58 +33,6 @@ static struct fuse_lowlevel_ops const filesystem_operations =
.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)
{
@ -90,32 +44,17 @@ static void wf_impl_filesystem_cleanup(
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);
}
}
wf_mountpoint_dispose(filesystem->mountpoint);
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)
char const * name,
struct wf_mountpoint * mountpoint)
{
bool result = false;
@ -129,15 +68,7 @@ static bool wf_impl_filesystem_init(
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->mountpoint = mountpoint;
filesystem->session = fuse_session_new(
&filesystem->args,
@ -146,7 +77,8 @@ static bool wf_impl_filesystem_init(
&filesystem->user_data);
if (NULL != filesystem->session)
{
result = (0 == fuse_session_mount(filesystem->session, filesystem->root_path));
char const * path = wf_mountpoint_get_path(filesystem->mountpoint);
result = (0 == fuse_session_mount(filesystem->session, path));
}
if (result)
@ -169,17 +101,15 @@ static bool wf_impl_filesystem_init(
struct wf_impl_filesystem * wf_impl_filesystem_create(
struct wf_impl_session * session,
char const * name)
char const * name,
struct wf_mountpoint * mountpoint)
{
struct wf_impl_filesystem * filesystem = malloc(sizeof(struct wf_impl_filesystem));
if (NULL != filesystem)
bool success = wf_impl_filesystem_init(filesystem, session, name, mountpoint);
if (!success)
{
bool success = wf_impl_filesystem_init(filesystem, session, name);
if (!success)
{
free(filesystem);
filesystem = NULL;
}
free(filesystem);
filesystem = NULL;
}
return filesystem;
@ -200,9 +130,4 @@ void wf_impl_filesystem_process_request(
{
fuse_session_process_buf(filesystem->session, &filesystem->buffer);
}
else if (-EINTR != result)
{
// ToDo
}
}

@ -6,7 +6,7 @@
#endif
#include "webfuse/adapter/impl/fuse_wrapper.h"
#include "webfuse/adapter/impl/operations.h"
#include "webfuse/adapter/impl/operation/context.h"
#include "webfuse/core/slist.h"
#ifdef __cplusplus
@ -14,6 +14,7 @@ extern "C"
{
#endif
struct wf_mountpoint;
struct wf_impl_session;
struct lws;
@ -23,18 +24,15 @@ struct wf_impl_filesystem
struct fuse_args args;
struct fuse_session * session;
struct fuse_buf buffer;
struct wf_impl_operations_context user_data;
struct wf_impl_operation_context user_data;
struct lws * wsi;
char * name;
char * id;
char * service_path;
char * default_path;
char * root_path;
struct wf_mountpoint * mountpoint;
};
extern struct wf_impl_filesystem * wf_impl_filesystem_create(
struct wf_impl_session * session,
char const * name);
char const * name,
struct wf_mountpoint * mountpoint);
extern void wf_impl_filesystem_dispose(
struct wf_impl_filesystem * filesystem);

@ -1,27 +0,0 @@
#include "webfuse/adapter/impl/jsonrpc/method.h"
#include <stdlib.h>
#include <string.h>
struct wf_impl_jsonrpc_method * wf_impl_jsonrpc_method_create(
char const * method_name,
wf_impl_jsonrpc_method_invoke_fn * invoke,
void * user_data)
{
struct wf_impl_jsonrpc_method * method = malloc(sizeof(struct wf_impl_jsonrpc_method));
if (NULL != method)
{
method->next = NULL;
method->name = strdup(method_name);
method->invoke = invoke;
method->user_data = user_data;
}
return method;
}
void wf_impl_jsonrpc_method_dispose(
struct wf_impl_jsonrpc_method * method)
{
free(method->name);
free(method);
}

@ -1,40 +0,0 @@
#ifndef WF_ADAPTER_IMPL_JSONRPC_METHOD_H
#define WF_ADAPTER_IMPL_JSONRPC_METHOD_H
#include <jansson.h>
#ifdef __cplusplus
extern "C"
{
#endif
struct wf_impl_jsonrpc_request;
typedef void wf_impl_jsonrpc_method_invoke_fn(
struct wf_impl_jsonrpc_request * request,
char const * method_name,
json_t * params,
void * user_data);
struct wf_impl_jsonrpc_method
{
struct wf_impl_jsonrpc_method * next;
char * name;
wf_impl_jsonrpc_method_invoke_fn * invoke;
void * user_data;
};
extern struct wf_impl_jsonrpc_method * wf_impl_jsonrpc_method_create(
char const * method_name,
wf_impl_jsonrpc_method_invoke_fn * invoke,
void * user_data);
extern void wf_impl_jsonrpc_method_dispose(
struct wf_impl_jsonrpc_method * method);
#ifdef __cplusplus
}
#endif
#endif

@ -1,194 +0,0 @@
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include <string.h>
#include "webfuse/adapter/impl/jsonrpc/response.h"
static void wf_impl_jsonrpc_proxy_timeout(
struct wf_impl_timer * timer)
{
struct wf_impl_jsonrpc_proxy * proxy = timer->user_data;
if (proxy->request.is_pending)
{
wf_impl_jsonrpc_proxy_finished_fn * finished = proxy->request.finished;
void * user_data = proxy->request.user_data;
proxy->request.is_pending = false;
proxy->request.id = 0;
proxy->request.user_data = NULL;
proxy->request.finished = NULL;
wf_impl_timer_cancel(&proxy->request.timer);
finished(user_data, WF_BAD_TIMEOUT, NULL);
}
}
static json_t * wf_impl_jsonrpc_request_create(
char const * method,
int id,
char const * param_info,
va_list args)
{
json_t * request = json_object();
json_object_set_new(request, "method", json_string(method));
json_t * params = json_array();
for (char const * param_type = param_info; '\0' != *param_type; param_type++)
{
switch(*param_type)
{
case 's':
{
char const * const value = va_arg(args, char const *);
json_array_append_new(params, json_string(value));
}
break;
case 'i':
{
int const value = va_arg(args, int);
json_array_append_new(params, json_integer(value));
}
break;
default:
fprintf(stderr, "fatal: unknown param_type '%c'\n", *param_type);
json_decref(params);
json_decref(request);
return NULL;
}
}
json_object_set_new(request, "params", params);
if (0 != id)
{
json_object_set_new(request, "id", json_integer(id));
}
return request;
}
void wf_impl_jsonrpc_proxy_init(
struct wf_impl_jsonrpc_proxy * proxy,
struct wf_impl_timeout_manager * timeout_manager,
int timeout,
wf_impl_jsonrpc_send_fn * send,
void * user_data)
{
proxy->send = send;
proxy->timeout = timeout;
proxy->user_data = user_data;
proxy->request.is_pending = false;
wf_impl_timer_init(&proxy->request.timer, timeout_manager);
}
void wf_impl_jsonrpc_proxy_cleanup(
struct wf_impl_jsonrpc_proxy * proxy)
{
if (proxy->request.is_pending)
{
void * user_data = proxy->request.user_data;
wf_impl_jsonrpc_proxy_finished_fn * finished = proxy->request.finished;
proxy->request.is_pending = false;
proxy->request.finished = NULL;
proxy->request.user_data = NULL;
proxy->request.id = 0;
wf_impl_timer_cancel(&proxy->request.timer);
finished(user_data, WF_BAD, NULL);
}
wf_impl_timer_cleanup(&proxy->request.timer);
}
void wf_impl_jsonrpc_proxy_invoke(
struct wf_impl_jsonrpc_proxy * proxy,
wf_impl_jsonrpc_proxy_finished_fn * finished,
void * user_data,
char const * method_name,
char const * param_info,
...
)
{
if (!proxy->request.is_pending)
{
proxy->request.is_pending = true;
proxy->request.finished = finished;
proxy->request.user_data = user_data;
proxy->request.id = 42;
wf_impl_timer_start(&proxy->request.timer, wf_impl_timepoint_in_msec(proxy->timeout),
&wf_impl_jsonrpc_proxy_timeout, proxy);
va_list args;
va_start(args, param_info);
json_t * request = wf_impl_jsonrpc_request_create(method_name, proxy->request.id, param_info, args);
va_end(args);
bool const is_send = ((NULL != request) && (proxy->send(request, proxy->user_data)));
if (!is_send)
{
proxy->request.is_pending = false;
proxy->request.finished = NULL;
proxy->request.user_data = NULL;
proxy->request.id = 0;
wf_impl_timer_cancel(&proxy->request.timer);
finished(user_data, WF_BAD, NULL);
}
if (NULL != request)
{
json_decref(request);
}
}
else
{
finished(user_data, WF_BAD_BUSY, NULL);
}
}
extern void wf_impl_jsonrpc_proxy_notify(
struct wf_impl_jsonrpc_proxy * proxy,
char const * method_name,
char const * param_info,
...
)
{
va_list args;
va_start(args, param_info);
json_t * request = wf_impl_jsonrpc_request_create(method_name, 0, param_info, args);
va_end(args);
if (NULL != request)
{
proxy->send(request, proxy->user_data);
json_decref(request);
}
}
void wf_impl_jsonrpc_proxy_onresult(
struct wf_impl_jsonrpc_proxy * proxy,
json_t * message)
{
struct wf_impl_jsonrpc_response response;
wf_impl_jsonrpc_response_init(&response, message);
if ((proxy->request.is_pending) && (response.id == proxy->request.id))
{
wf_impl_jsonrpc_proxy_finished_fn * finished = proxy->request.finished;
void * user_data = proxy->request.user_data;
proxy->request.is_pending = false;
proxy->request.id = 0;
proxy->request.user_data = NULL;
proxy->request.finished = NULL;
wf_impl_timer_cancel(&proxy->request.timer);
finished(user_data, response.status, response.result);
}
wf_impl_jsonrpc_response_cleanup(&response);
}

@ -1,82 +0,0 @@
#ifndef WF_ADAPTER_IMPL_JSONRPC_PROXY_H
#define WF_ADAPTER_IMPL_JSONRPC_PROXY_H
#ifndef __cplusplus
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#else
#include <cstdarg>
#include <cstddef>
using std::size_t;
#endif
#include <jansson.h>
#include "webfuse/adapter/impl/jsonrpc/send_fn.h"
#include "webfuse/adapter/impl/time/timeout_manager.h"
#include "webfuse/adapter/impl/time/timer.h"
#include "webfuse/core/status.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void wf_impl_jsonrpc_proxy_finished_fn(
void * user_data,
wf_status status,
struct json_t const * result);
struct wf_impl_jsonrpc_request
{
bool is_pending;
wf_impl_jsonrpc_proxy_finished_fn * finished;
void * user_data;
int id;
struct wf_impl_timer timer;
};
struct wf_impl_jsonrpc_proxy
{
struct wf_impl_jsonrpc_request request;
int timeout;
wf_impl_jsonrpc_send_fn * send;
void * user_data;
};
extern void wf_impl_jsonrpc_proxy_init(
struct wf_impl_jsonrpc_proxy * proxy,
struct wf_impl_timeout_manager * manager,
int timeout,
wf_impl_jsonrpc_send_fn * send,
void * user_data);
extern void wf_impl_jsonrpc_proxy_cleanup(
struct wf_impl_jsonrpc_proxy * proxy);
extern void wf_impl_jsonrpc_proxy_invoke(
struct wf_impl_jsonrpc_proxy * proxy,
wf_impl_jsonrpc_proxy_finished_fn * finished,
void * user_data,
char const * method_name,
char const * param_info,
...
);
extern void wf_impl_jsonrpc_proxy_notify(
struct wf_impl_jsonrpc_proxy * proxy,
char const * method_name,
char const * param_info,
...
);
extern void wf_impl_jsonrpc_proxy_onresult(
struct wf_impl_jsonrpc_proxy * proxy,
json_t * message);
#ifdef __cplusplus
}
#endif
#endif

@ -1,82 +0,0 @@
#include "webfuse/adapter/impl/jsonrpc/request.h"
#include "webfuse/core/status_intern.h"
#include <stdlib.h>
struct wf_impl_jsonrpc_request
{
int id;
wf_impl_jsonrpc_send_fn * send;
void * user_data;
};
bool wf_impl_jsonrpc_is_request(
json_t * message)
{
json_t * id = json_object_get(message, "id");
json_t * method = json_object_get(message, "method");
json_t * params = json_object_get(message, "params");
return (json_is_integer(id) && json_is_string(method) &&
(json_is_array(params) || json_is_object(params)));
}
struct wf_impl_jsonrpc_request * wf_impl_jsonrpc_request_create(
int id,
wf_impl_jsonrpc_send_fn * send,
void * user_data)
{
struct wf_impl_jsonrpc_request * request = malloc(sizeof(struct wf_impl_jsonrpc_request));
if (NULL != request)
{
request->id = id;
request->send = send;
request->user_data = user_data;
}
return request;
}
void wf_impl_jsonrpc_request_dispose(
struct wf_impl_jsonrpc_request * request)
{
free(request);
}
void * wf_impl_jsonrpc_request_get_userdata(
struct wf_impl_jsonrpc_request * request)
{
return request->user_data;
}
void wf_impl_jsonrpc_respond(
struct wf_impl_jsonrpc_request * request,
json_t * result)
{
json_t * response = json_object();
json_object_set_new(response, "result", result);
json_object_set_new(response, "id", json_integer(request->id));
request->send(response, request->user_data);
json_decref(response);
wf_impl_jsonrpc_request_dispose(request);
}
void wf_impl_jsonrpc_respond_error(
struct wf_impl_jsonrpc_request * request,
wf_status status)
{
json_t * err = json_object();
json_object_set_new(err, "code", json_integer(status));
json_object_set_new(err, "message", json_string(wf_status_tostring(status)));
json_t * response = json_object();
json_object_set_new(response, "error", err);
json_object_set_new(response, "id", json_integer(request->id));
request->send(response, request->user_data);
json_decref(response);
wf_impl_jsonrpc_request_dispose(request);
}

@ -1,52 +0,0 @@
#ifndef WF_ADAPTER_IMPL_JSONRPC_REQUEST_H
#define WF_ADAPTER_IMPL_JSONRPC_REQUEST_H
#ifndef __cplusplus
#include <stdarg.h>
#include <stddef.h>
#include <stdbool.h>
#else
#include <cstdarg>
#include <cstddef>
using std::size_t;
#endif
#include <jansson.h>
#include "webfuse/core/status.h"
#include "webfuse/adapter/impl/jsonrpc/send_fn.h"
#ifdef __cplusplus
extern "C"
{
#endif
struct wf_impl_jsonrpc_request;
extern bool wf_impl_jsonrpc_is_request(
json_t * message);
extern struct wf_impl_jsonrpc_request * wf_impl_jsonrpc_request_create(
int id,
wf_impl_jsonrpc_send_fn * send,
void * user_data);
extern void wf_impl_jsonrpc_request_dispose(
struct wf_impl_jsonrpc_request * request);
extern void * wf_impl_jsonrpc_request_get_userdata(
struct wf_impl_jsonrpc_request * request);
extern void wf_impl_jsonrpc_respond(
struct wf_impl_jsonrpc_request * request,
json_t * result);
extern void wf_impl_jsonrpc_respond_error(
struct wf_impl_jsonrpc_request * request,
wf_status status);
#ifdef __cplusplus
}
#endif
#endif

@ -1,60 +0,0 @@
#include "webfuse/adapter/impl/jsonrpc/response.h"
extern bool wf_impl_jsonrpc_is_response(
json_t * message)
{
json_t * id = json_object_get(message, "id");
json_t * err = json_object_get(message, "error");
json_t * result = json_object_get(message, "result");
return (json_is_integer(id) &&
(json_is_object(err) || (NULL != result)));
}
void wf_impl_jsonrpc_response_init(
struct wf_impl_jsonrpc_response * result,
json_t * response)
{
result->status = WF_BAD;
result->id = -1;
result->result = NULL;
json_t * id_holder = json_object_get(response, "id");
if ((NULL == id_holder) || (!json_is_integer(id_holder)))
{
result->status = WF_BAD_FORMAT;
return;
}
result->status = WF_GOOD;
result->id = json_integer_value(id_holder);
result->result = json_object_get(response, "result");
if (NULL != result->result)
{
json_incref(result->result);
}
else
{
result->status = WF_BAD_FORMAT;
json_t * error = json_object_get(response, "error");
if (NULL != error)
{
json_t * error_code = json_object_get(error, "code");
if ((NULL != error_code) && (json_is_integer(error_code)))
{
result->status = json_integer_value(error_code);
}
}
}
}
void wf_impl_jsonrpc_response_cleanup(
struct wf_impl_jsonrpc_response * response)
{
if (NULL != response->result)
{
json_decref(response->result);
}
}

@ -1,41 +0,0 @@
#ifndef WF_ADAPTER_IMPL_JSONRPC_RESPONSE_H
#define WF_ADAPTER_IMPL_JSONRPC_RESPONSE_H
#ifndef __cplusplus
#include <stdbool.h>
#include <stddef.h>
#else
#include <cstddef>
using std::size_t;
#endif
#include <jansson.h>
#include "webfuse/core/status.h"
#ifdef __cplusplus
extern "C" {
#endif
struct wf_impl_jsonrpc_response
{
wf_status status;
int id;
json_t * result;
};
extern bool wf_impl_jsonrpc_is_response(
json_t * message);
extern void wf_impl_jsonrpc_response_init(
struct wf_impl_jsonrpc_response * response,
json_t * message);
extern void wf_impl_jsonrpc_response_cleanup(
struct wf_impl_jsonrpc_response * response);
#ifdef __cplusplus
}
#endif
#endif

@ -1,95 +0,0 @@
#include "webfuse/adapter/impl/jsonrpc/server.h"
#include "webfuse/adapter/impl/jsonrpc/method.h"
#include "webfuse/adapter/impl/jsonrpc/request.h"
#include "webfuse/core/util.h"
#include <string.h>
void wf_impl_jsonrpc_server_init(
struct wf_impl_jsonrpc_server * server)
{
server->methods = NULL;
}
void wf_impl_jsonrpc_server_cleanup(
struct wf_impl_jsonrpc_server * server)
{
struct wf_impl_jsonrpc_method * current = server->methods;
while (NULL != current)
{
struct wf_impl_jsonrpc_method * next = current->next;
wf_impl_jsonrpc_method_dispose(current);
current = next;
}
server->methods = NULL;
}
void wf_impl_jsonrpc_server_add(
struct wf_impl_jsonrpc_server * server,
char const * method_name,
wf_impl_jsonrpc_method_invoke_fn * invoke,
void * user_data)
{
struct wf_impl_jsonrpc_method * method = wf_impl_jsonrpc_method_create(method_name, invoke, user_data);
method->next = server->methods;
server->methods = method;
}
static void wf_impl_jsonrpc_server_invalid_method_invoke(
struct wf_impl_jsonrpc_request * request,
char const * WF_UNUSED_PARAM(method_name),
json_t * WF_UNUSED_PARAM(params),
void * WF_UNUSED_PARAM(user_data))
{
wf_impl_jsonrpc_respond_error(request, WF_BAD_NOTIMPLEMENTED);
}
static struct wf_impl_jsonrpc_method const wf_impl_jsonrpc_server_invalid_method =
{
.next = NULL,
.name = "<invalid>",
.invoke = &wf_impl_jsonrpc_server_invalid_method_invoke,
.user_data = NULL
};
static struct wf_impl_jsonrpc_method const * wf_impl_jsonrpc_server_get_method(
struct wf_impl_jsonrpc_server * server,
char const * method_name)
{
struct wf_impl_jsonrpc_method const * current = server->methods;
while (NULL != current)
{
if (0 == strcmp(method_name, current->name))
{
return current;
}
current = current->next;
}
return &wf_impl_jsonrpc_server_invalid_method;
}
void wf_impl_jsonrpc_server_process(
struct wf_impl_jsonrpc_server * server,
json_t * request_data,
wf_impl_jsonrpc_send_fn * send,
void * user_data)
{
json_t * method_holder = json_object_get(request_data, "method");
json_t * params = json_object_get(request_data, "params");
json_t * id_holder = json_object_get(request_data, "id");
if (json_is_string(method_holder) &&
(json_is_array(params) || (json_is_object(params))) &&
json_is_integer(id_holder))
{
char const * method_name = json_string_value(method_holder);
int id = json_integer_value(id_holder);
struct wf_impl_jsonrpc_request * request = wf_impl_jsonrpc_request_create(id, send, user_data);
struct wf_impl_jsonrpc_method const * method = wf_impl_jsonrpc_server_get_method(server, method_name);
method->invoke(request, method_name, params, method->user_data);
}
}

@ -1,48 +0,0 @@
#ifndef WF_ADAPTER_IMPL_JSONRPC_SERVER_H
#define WF_ADAPTER_IMPL_JSONRPC_SERVER_H
#ifndef __cplusplus
#include <stdarg.h>
#include <stdbool.h>
#else
#include <cstdarg>
#endif
#include <jansson.h>
#include "webfuse/core/status.h"
#include "webfuse/adapter/impl/jsonrpc/send_fn.h"
#include "webfuse/adapter/impl/jsonrpc/method.h"
#ifdef __cplusplus
extern "C"
{
#endif
struct wf_impl_jsonrpc_server
{
struct wf_impl_jsonrpc_method * methods;
};
extern void wf_impl_jsonrpc_server_init(
struct wf_impl_jsonrpc_server * server);
extern void wf_impl_jsonrpc_server_cleanup(
struct wf_impl_jsonrpc_server * server);
extern void wf_impl_jsonrpc_server_add(
struct wf_impl_jsonrpc_server * server,
char const * method_name,
wf_impl_jsonrpc_method_invoke_fn * invoke,
void * user_data);
extern void wf_impl_jsonrpc_server_process(
struct wf_impl_jsonrpc_server * server,
json_t * request,
wf_impl_jsonrpc_send_fn * send,
void * user_data);
#ifdef __cplusplus
}
#endif
#endif

@ -1,17 +0,0 @@
#ifndef WF_ADAPTER_IMPL_JSON_UTIL_H
#define WF_ADAPTER_IMPL_JSON_UTIL_H
#include <jansson.h>
#ifdef __cplusplus
extern "C"
{
#endif
extern int wf_impl_json_get_int(json_t const * object, char const * key, int default_value);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,53 @@
#include "webfuse/adapter/impl/mountpoint.h"
#include <stdlib.h>
#include <string.h>
struct wf_mountpoint
{
char * path;
void * user_data;
wf_mountpoint_userdata_dispose_fn * dispose;
};
struct wf_mountpoint *
wf_impl_mountpoint_create(
char const * path)
{
struct wf_mountpoint * mountpoint = malloc(sizeof(struct wf_mountpoint));
mountpoint->path = strdup(path);
mountpoint->user_data = NULL;
mountpoint->dispose = NULL;
return mountpoint;
}
void
wf_impl_mountpoint_dispose(
struct wf_mountpoint * mountpoint)
{
if (NULL != mountpoint->dispose)
{
mountpoint->dispose(mountpoint->user_data);
}
free(mountpoint->path);
free(mountpoint);
}
char const *
wf_impl_mountpoint_get_path(
struct wf_mountpoint const * mountpoint)
{
return mountpoint->path;
}
extern void
wf_impl_mountpoint_set_userdata(
struct wf_mountpoint * mountpoint,
void * user_data,
wf_mountpoint_userdata_dispose_fn * dispose)
{
mountpoint->user_data = user_data;
mountpoint->dispose = dispose;
}

@ -0,0 +1,33 @@
#ifndef WF_IMPL_MOUNTPOINT_H
#define WF_IMPL_MOUNTPOINT_H
#include "webfuse/adapter/mountpoint.h"
#ifdef __cplusplus
extern "C"
{
#endif
extern struct wf_mountpoint *
wf_impl_mountpoint_create(
char const * path);
extern void
wf_impl_mountpoint_dispose(
struct wf_mountpoint * mountpoint);
extern char const *
wf_impl_mountpoint_get_path(
struct wf_mountpoint const * mountpoint);
extern void
wf_impl_mountpoint_set_userdata(
struct wf_mountpoint * mountpoint,
void * user_data,
wf_mountpoint_userdata_dispose_fn * dispose);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,54 @@
#include "webfuse/adapter/impl/mountpoint_factory.h"
#include <stddef.h>
void
wf_impl_mountpoint_factory_init_default(
struct wf_impl_mountpoint_factory * factory)
{
factory->create_mountpoint = NULL;
factory->user_data = NULL;
}
void
wf_impl_mountpoint_factory_init(
struct wf_impl_mountpoint_factory * factory,
wf_create_mountpoint_fn * create_mountpoint,
void * user_data)
{
factory->create_mountpoint = create_mountpoint;
factory->user_data = user_data;
}
void
wf_impl_mountpoint_factory_clone(
struct wf_impl_mountpoint_factory * factory,
struct wf_impl_mountpoint_factory * other)
{
other->create_mountpoint = factory->create_mountpoint;
other->user_data = factory->user_data;
}
bool
wf_impl_mountpoint_factory_isvalid(
struct wf_impl_mountpoint_factory * factory)
{
return (NULL != factory->create_mountpoint);
}
void
wf_impl_mountpoint_factory_cleanup(
struct wf_impl_mountpoint_factory * factory)
{
factory->create_mountpoint = NULL;
factory->user_data = NULL;
}
struct wf_mountpoint *
wf_impl_mountpoint_factory_create_mountpoint(
struct wf_impl_mountpoint_factory * factory,
char const * filesystem)
{
return factory->create_mountpoint(filesystem, factory->user_data);
}

@ -0,0 +1,55 @@
#ifndef WF_ADAPTER_IMPL_MOUNTPOINT_FACTORY_H
#define WF_ADAPTER_IMPL_MOUNTPOINT_FACTORY_H
#include "webfuse/adapter/mountpoint_factory.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C"
{
#endif
struct wf_impl_mountpoint_factory
{
wf_create_mountpoint_fn * create_mountpoint;
void * user_data;
};
extern void
wf_impl_mountpoint_factory_init_default(
struct wf_impl_mountpoint_factory * factory);
extern void
wf_impl_mountpoint_factory_init(
struct wf_impl_mountpoint_factory * factory,
wf_create_mountpoint_fn * create_mountpoint,
void * user_data);
extern void
wf_impl_mountpoint_factory_clone(
struct wf_impl_mountpoint_factory * factory,
struct wf_impl_mountpoint_factory * other);
extern bool
wf_impl_mountpoint_factory_isvalid(
struct wf_impl_mountpoint_factory * factory);
extern void
wf_impl_mountpoint_factory_init_from(
struct wf_impl_mountpoint_factory * factory,
struct wf_impl_mountpoint_factory * other);
extern void
wf_impl_mountpoint_factory_cleanup(
struct wf_impl_mountpoint_factory * factory);
extern struct wf_mountpoint *
wf_impl_mountpoint_factory_create_mountpoint(
struct wf_impl_mountpoint_factory * factory,
char const * filesystem);
#ifdef __cplusplus
}
#endif
#endif

@ -1,10 +1,11 @@
#include "webfuse/adapter/impl/operations.h"
#include "webfuse/adapter/impl/operation/close.h"
#include "webfuse/adapter/impl/operation/context.h"
#include <limits.h>
#include <errno.h>
#include <jansson.h>
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/core/jsonrpc/proxy.h"
#include "webfuse/core/util.h"
void wf_impl_operation_close(
@ -12,13 +13,13 @@ void wf_impl_operation_close(
fuse_ino_t inode,
struct fuse_file_info * file_info)
{
struct wf_impl_operations_context * user_data = fuse_req_userdata(request);
struct wf_impl_jsonrpc_proxy * rpc = wf_impl_operations_context_get_proxy(user_data);
struct wf_impl_operation_context * user_data = fuse_req_userdata(request);
struct wf_jsonrpc_proxy * rpc = wf_impl_operation_context_get_proxy(user_data);
if (NULL != rpc)
{
int handle = (int) (file_info->fh & INT_MAX);
wf_impl_jsonrpc_proxy_notify(rpc, "close", "siii", user_data->name, inode, handle, file_info->flags);
wf_jsonrpc_proxy_notify(rpc, "close", "siii", user_data->name, inode, handle, file_info->flags);
}
fuse_reply_err(request, 0);

@ -0,0 +1,20 @@
#ifndef WF_ADAPTER_IMPL_OPERATION_CLOSE_H
#define WF_ADAPTER_IMPL_OPERATION_CLOSE_H
#include "webfuse/adapter/impl/fuse_wrapper.h"
#ifdef __cplusplus
extern "C"
{
#endif
extern void wf_impl_operation_close(
fuse_req_t request,
fuse_ino_t inode,
struct fuse_file_info * file_info);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,18 @@
#include "webfuse/adapter/impl/operation/context.h"
#include "webfuse/adapter/impl/session_manager.h"
#include "webfuse/adapter/impl/session.h"
#include <stddef.h>
struct wf_jsonrpc_proxy * wf_impl_operation_context_get_proxy(
struct wf_impl_operation_context * context)
{
struct wf_jsonrpc_proxy * proxy = NULL;
struct wf_impl_session * session = context->session;
if (NULL != session)
{
proxy = session->rpc;
}
return proxy;
}

@ -0,0 +1,28 @@
#ifndef WF_ADAPTER_IMPL_OPERATION_CONTEXT_H
#define WF_ADAPTER_IMPL_OPERATION_CONTEXT_H
#include "webfuse/adapter/impl/fuse_wrapper.h"
#ifdef __cplusplus
extern "C" {
#endif
struct wf_impl_session;
struct wf_jsonrpc_proxy;
struct wf_impl_operation_context
{
struct wf_impl_session * session;
double timeout;
char * name;
};
extern struct wf_jsonrpc_proxy * wf_impl_operation_context_get_proxy(
struct wf_impl_operation_context * context);
#ifdef __cplusplus
}
#endif
#endif

@ -1,4 +1,5 @@
#include "webfuse/adapter/impl/operations.h"
#include "webfuse/adapter/impl/operation/getattr.h"
#include "webfuse/adapter/impl/operation/context.h"
#include <errno.h>
#include <string.h>
@ -7,35 +8,28 @@
#include <sys/stat.h>
#include <unistd.h>
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/adapter/impl/jsonrpc/util.h"
#include "webfuse/core/jsonrpc/proxy.h"
#include "webfuse/core/json_util.h"
#include "webfuse/core/util.h"
struct wf_impl_operation_getattr_context
{
fuse_req_t request;
double timeout;
uid_t uid;
gid_t gid;
};
static void wf_impl_operation_getattr_finished(
void wf_impl_operation_getattr_finished(
void * user_data,
wf_status status,
json_t const * data)
json_t const * result,
json_t const * error)
{
wf_status status = wf_impl_jsonrpc_get_status(error);
struct wf_impl_operation_getattr_context * context = user_data;
struct stat buffer;
if (NULL != data)
if (NULL != result)
{
json_t * mode_holder = json_object_get(data, "mode");
json_t * type_holder = json_object_get(data, "type");
if ((NULL != mode_holder) && (json_is_integer(mode_holder)) &&
(NULL != type_holder) && (json_is_string(type_holder)))
json_t * mode_holder = json_object_get(result, "mode");
json_t * type_holder = json_object_get(result, "type");
if ((json_is_integer(mode_holder)) && (json_is_string(type_holder)))
{
memset(&buffer, 0, sizeof(struct stat));
buffer.st_ino = context->inode;
buffer.st_mode = json_integer_value(mode_holder) & 0555;
char const * type = json_string_value(type_holder);
if (0 == strcmp("file", type))
@ -50,11 +44,10 @@ static void wf_impl_operation_getattr_finished(
buffer.st_uid = context->uid;
buffer.st_gid = context->gid;
buffer.st_nlink = 1;
buffer.st_size = wf_impl_json_get_int(data, "size", 0);
buffer.st_atime = wf_impl_json_get_int(data, "atime", 0);
buffer.st_mtime = wf_impl_json_get_int(data, "mtime", 0);
buffer.st_ctime = wf_impl_json_get_int(data, "ctime", 0);
buffer.st_size = wf_impl_json_get_int(result, "size", 0);
buffer.st_atime = wf_impl_json_get_int(result, "atime", 0);
buffer.st_mtime = wf_impl_json_get_int(result, "mtime", 0);
buffer.st_ctime = wf_impl_json_get_int(result, "ctime", 0);
}
else
{
@ -80,18 +73,19 @@ void wf_impl_operation_getattr (
struct fuse_file_info * WF_UNUSED_PARAM(file_info))
{
struct fuse_ctx const * context = fuse_req_ctx(request);
struct wf_impl_operations_context * user_data = fuse_req_userdata(request);
struct wf_impl_jsonrpc_proxy * rpc = wf_impl_operations_context_get_proxy(user_data);
struct wf_impl_operation_context * user_data = fuse_req_userdata(request);
struct wf_jsonrpc_proxy * rpc = wf_impl_operation_context_get_proxy(user_data);
if (NULL != rpc)
{
struct wf_impl_operation_getattr_context * getattr_context = malloc(sizeof(struct wf_impl_operation_getattr_context));
getattr_context->request = request;
getattr_context->inode = inode;
getattr_context->uid = context->uid;
getattr_context->gid = context->gid;
getattr_context->timeout = user_data->timeout;
wf_impl_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_getattr_finished, getattr_context, "getattr", "si", user_data->name, inode);
wf_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_getattr_finished, getattr_context, "getattr", "si", user_data->name, inode);
}
else
{

@ -0,0 +1,37 @@
#ifndef WF_ADAPTER_IMPL_OPERATION_GETATTR_H
#define WF_ADAPTER_IMPL_OPERATION_GETATTR_H
#include "webfuse/adapter/impl/fuse_wrapper.h"
#include <jansson.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C"
{
#endif
struct wf_impl_operation_getattr_context
{
fuse_req_t request;
fuse_ino_t inode;
double timeout;
uid_t uid;
gid_t gid;
};
extern void wf_impl_operation_getattr_finished(
void * user_data,
json_t const * result,
json_t const * error);
extern void wf_impl_operation_getattr (
fuse_req_t request,
fuse_ino_t inode,
struct fuse_file_info *file_info);
#ifdef __cplusplus
}
#endif
#endif

@ -1,4 +1,5 @@
#include "webfuse/adapter/impl/operations.h"
#include "webfuse/adapter/impl/operation/lookup.h"
#include "webfuse/adapter/impl/operation/context.h"
#include <limits.h>
#include <errno.h>
@ -10,39 +11,33 @@
#include <stdlib.h>
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/adapter/impl/jsonrpc/util.h"
#include "webfuse/core/jsonrpc/proxy.h"
#include "webfuse/core/json_util.h"
#include "webfuse/core/util.h"
struct wf_impl_operation_lookup_context
{
fuse_req_t request;
double timeout;
uid_t uid;
gid_t gid;
};
static void wf_impl_operation_lookup_finished(
void wf_impl_operation_lookup_finished(
void * user_data,
wf_status status,
json_t const * data
json_t const * result,
json_t const * error
)
{
wf_status status = wf_impl_jsonrpc_get_status(error);
struct wf_impl_operation_lookup_context * context = user_data;
struct fuse_entry_param buffer;
if (NULL != data)
if (NULL != result)
{
json_t * inode_holder = json_object_get(data, "inode");
json_t * mode_holder = json_object_get(data, "mode");
json_t * type_holder = json_object_get(data, "type");
if ((NULL != inode_holder) && (json_is_integer(inode_holder)) &&
(NULL != mode_holder) && (json_is_integer(mode_holder)) &&
(NULL != type_holder) && (json_is_string(type_holder)))
json_t * inode_holder = json_object_get(result, "inode");
json_t * mode_holder = json_object_get(result, "mode");
json_t * type_holder = json_object_get(result, "type");
if ((json_is_integer(inode_holder)) &&
(json_is_integer(mode_holder)) &&
(json_is_string(type_holder)))
{
memset(&buffer, 0, sizeof(struct stat));
buffer.ino = json_integer_value(inode_holder);
buffer.attr.st_ino = buffer.ino;
buffer.attr.st_mode = json_integer_value(mode_holder) & 0555;
char const * type = json_string_value(type_holder);
if (0 == strcmp("file", type))
@ -60,10 +55,10 @@ static void wf_impl_operation_lookup_finished(
buffer.attr.st_uid = context->uid;
buffer.attr.st_gid = context->gid;
buffer.attr.st_nlink = 1;
buffer.attr.st_size = wf_impl_json_get_int(data, "size", 0);
buffer.attr.st_atime = wf_impl_json_get_int(data, "atime", 0);
buffer.attr.st_mtime = wf_impl_json_get_int(data, "mtime", 0);
buffer.attr.st_ctime = wf_impl_json_get_int(data, "ctime", 0);
buffer.attr.st_size = wf_impl_json_get_int(result, "size", 0);
buffer.attr.st_atime = wf_impl_json_get_int(result, "atime", 0);
buffer.attr.st_mtime = wf_impl_json_get_int(result, "mtime", 0);
buffer.attr.st_ctime = wf_impl_json_get_int(result, "ctime", 0);
}
else
{
@ -89,8 +84,8 @@ void wf_impl_operation_lookup (
char const * name)
{
struct fuse_ctx const * context = fuse_req_ctx(request);
struct wf_impl_operations_context * user_data = fuse_req_userdata(request);
struct wf_impl_jsonrpc_proxy * rpc = wf_impl_operations_context_get_proxy(user_data);
struct wf_impl_operation_context * user_data = fuse_req_userdata(request);
struct wf_jsonrpc_proxy * rpc = wf_impl_operation_context_get_proxy(user_data);
if (NULL != rpc)
{
@ -100,7 +95,7 @@ void wf_impl_operation_lookup (
lookup_context->gid = context->gid;
lookup_context->timeout = user_data->timeout;
wf_impl_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_lookup_finished, lookup_context, "lookup", "sis", user_data->name, (int) (parent & INT_MAX), name);
wf_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_lookup_finished, lookup_context, "lookup", "sis", user_data->name, (int) (parent & INT_MAX), name);
}
else
{

@ -0,0 +1,36 @@
#ifndef WF_ADAPTER_IMPL_OPERATION_LOOKUP_H
#define WF_ADAPTER_IMPL_OPERATION_LOOKUP_H
#include "webfuse/adapter/impl/fuse_wrapper.h"
#include <jansson.h>
#include <sys/types.h>
#ifdef __cplusplus
extern "C"
{
#endif
struct wf_impl_operation_lookup_context
{
fuse_req_t request;
double timeout;
uid_t uid;
gid_t gid;
};
extern void wf_impl_operation_lookup_finished(
void * user_data,
json_t const * result,
json_t const * error);
extern void wf_impl_operation_lookup (
fuse_req_t req,
fuse_ino_t parent,
char const * name);
#ifdef __cplusplus
}
#endif
#endif

@ -1,18 +1,20 @@
#include "webfuse/adapter/impl/operations.h"
#include "webfuse/adapter/impl/operation/open.h"
#include "webfuse/adapter/impl/operation/context.h"
#include <string.h>
#include <errno.h>
#include <jansson.h>
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/core/jsonrpc/proxy.h"
#include "webfuse/core/util.h"
#include "webfuse/core/status.h"
#include "webfuse/core/json_util.h"
#include <string.h>
#include <errno.h>
static void wf_impl_operation_open_finished(
void wf_impl_operation_open_finished(
void * user_data,
wf_status status,
json_t const * result)
json_t const * result,
json_t const * error)
{
wf_status status = wf_impl_jsonrpc_get_status(error);
fuse_req_t request = user_data;
struct fuse_file_info file_info;
memset(&file_info, 0, sizeof(struct fuse_file_info));
@ -20,7 +22,7 @@ static void wf_impl_operation_open_finished(
if (NULL != result)
{
json_t * handle_holder = json_object_get(result, "handle");
if ((NULL != handle_holder) && (json_is_integer(handle_holder)))
if (json_is_integer(handle_holder))
{
file_info.fh = json_integer_value(handle_holder);
}
@ -46,12 +48,12 @@ void wf_impl_operation_open(
fuse_ino_t inode,
struct fuse_file_info * file_info)
{
struct wf_impl_operations_context * user_data = fuse_req_userdata(request);
struct wf_impl_jsonrpc_proxy * rpc = wf_impl_operations_context_get_proxy(user_data);
struct wf_impl_operation_context * user_data = fuse_req_userdata(request);
struct wf_jsonrpc_proxy * rpc = wf_impl_operation_context_get_proxy(user_data);
if (NULL != rpc)
{
wf_impl_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_open_finished, request, "open", "sii", user_data->name, inode, file_info->flags);
wf_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_open_finished, request, "open", "sii", user_data->name, inode, file_info->flags);
}
else
{

@ -0,0 +1,26 @@
#ifndef WF_ADAPTER_IMPL_OPERATION_OPEN_H
#define WF_ADAPTER_IMPL_OPERATION_OPEN_H
#include "webfuse/adapter/impl/fuse_wrapper.h"
#include <jansson.h>
#ifdef __cplusplus
extern "C"
{
#endif
extern void wf_impl_operation_open(
fuse_req_t request,
fuse_ino_t inode,
struct fuse_file_info * file_info);
extern void wf_impl_operation_open_finished(
void * user_data,
json_t const * result,
json_t const * error);
#ifdef __cplusplus
}
#endif
#endif

@ -1,33 +1,47 @@
#include "webfuse/adapter/impl/operations.h"
#include "webfuse/adapter/impl/operation/read.h"
#include "webfuse/adapter/impl/operation/context.h"
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <jansson.h>
#include <libwebsockets.h>
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/core/jsonrpc/proxy.h"
#include "webfuse/core/base64.h"
#include "webfuse/core/json_util.h"
#define WF_MAX_READ_LENGTH 4096
static char * wf_impl_fill_buffer(
char * wf_impl_fill_buffer(
char const * data,
size_t data_size,
char const * format,
size_t count,
wf_status * status)
{
*status = WF_GOOD;
char * buffer = malloc(count + 1);
char * buffer = malloc(count);
if ((NULL != buffer) && (0 < count))
if (0 < count)
{
if (0 == strcmp("identity", format))
{
memcpy(buffer, data, count);
if (count == data_size)
{
memcpy(buffer, data, count);
}
else
{
*status = WF_BAD;
}
}
else if (0 == strcmp("base64", format))
{
lws_b64_decode_string(data, buffer, count + 1);
size_t result = wf_base64_decode(data, data_size, (uint8_t *) buffer, count);
if (result != count)
{
*status = WF_BAD;
}
}
else
{
@ -35,30 +49,41 @@ static char * wf_impl_fill_buffer(
}
}
if (WF_GOOD != *status)
{
free(buffer);
buffer = NULL;
}
return buffer;
}
static void wf_impl_operation_read_finished(void * user_data, wf_status status, json_t const * data)
void wf_impl_operation_read_finished(
void * user_data,
json_t const * result,
json_t const * error)
{
wf_status status = wf_impl_jsonrpc_get_status(error);
fuse_req_t request = user_data;
char * buffer = NULL;
size_t length = 0;
if (NULL != data)
if (NULL != result)
{
json_t * data_holder = json_object_get(data, "data");
json_t * format_holder = json_object_get(data, "format");
json_t * count_holder = json_object_get(data, "count");
json_t * data_holder = json_object_get(result, "data");
json_t * format_holder = json_object_get(result, "format");
json_t * count_holder = json_object_get(result, "count");
if (json_is_string(data_holder) &&
json_is_string(format_holder) &&
json_is_integer(count_holder))
{
char const * const data = json_string_value(data_holder);
size_t const data_size = json_string_length(data_holder);
char const * const format = json_string_value(format_holder);
length = (size_t) json_integer_value(count_holder);
buffer = wf_impl_fill_buffer(data, format, length, &status);
buffer = wf_impl_fill_buffer(data, data_size, format, length, &status);
}
else
{
@ -86,14 +111,14 @@ void wf_impl_operation_read(
off_t offset,
struct fuse_file_info * file_info)
{
struct wf_impl_operations_context * user_data = fuse_req_userdata(request);
struct wf_impl_jsonrpc_proxy * rpc = wf_impl_operations_context_get_proxy(user_data);
struct wf_impl_operation_context * user_data = fuse_req_userdata(request);
struct wf_jsonrpc_proxy * rpc = wf_impl_operation_context_get_proxy(user_data);
if (NULL != rpc)
{
int const length = (size <= WF_MAX_READ_LENGTH) ? (int) size : WF_MAX_READ_LENGTH;
int handle = (file_info->fh & INT_MAX);
wf_impl_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_read_finished, request, "read", "siiii", user_data->name, (int) inode, handle, (int) offset, length);
wf_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_read_finished, request, "read", "siiii", user_data->name, (int) inode, handle, (int) offset, length);
}
else
{

@ -0,0 +1,36 @@
#ifndef WF_ADAPTER_IMPL_OPERATION_READ_H
#define WF_ADAPTER_IMPL_OPERATION_READ_H
#include "webfuse/adapter/impl/fuse_wrapper.h"
#include "webfuse/core/status.h"
#include <jansson.h>
#ifdef __cplusplus
extern "C"
{
#endif
extern void wf_impl_operation_read(
fuse_req_t request,
fuse_ino_t ino, size_t size, off_t off,
struct fuse_file_info *fi);
extern char * wf_impl_fill_buffer(
char const * data,
size_t data_size,
char const * format,
size_t count,
wf_status * status);
extern void wf_impl_operation_read_finished(
void * user_data,
json_t const * result,
json_t const * error);
#ifdef __cplusplus
}
#endif
#endif

@ -1,4 +1,5 @@
#include "webfuse/adapter/impl/operations.h"
#include "webfuse/adapter/impl/operation/readdir.h"
#include "webfuse/adapter/impl/operation/context.h"
#include <stdlib.h>
#include <string.h>
@ -8,19 +9,13 @@
#include <sys/stat.h>
#include <unistd.h>
#include "webfuse/adapter/impl/jsonrpc/proxy.h"
#include "webfuse/core/jsonrpc/proxy.h"
#include "webfuse/core/util.h"
#include "webfuse/core/json_util.h"
#define WF_DIRBUFFER_INITIAL_SIZE 1024
struct wf_impl_operation_readdir_context
{
fuse_req_t request;
size_t size;
off_t offset;
};
struct wf_impl_dirbuffer
{
char * data;
@ -71,41 +66,51 @@ static size_t wf_impl_min(size_t a, size_t b)
return (a < b) ? a : b;
}
static void wf_impl_operation_readdir_finished(
void wf_impl_operation_readdir_finished(
void * user_data,
wf_status status,
json_t const * result)
json_t const * result,
json_t const * error)
{
wf_status status = wf_impl_jsonrpc_get_status(error);
struct wf_impl_operation_readdir_context * context = user_data;
struct wf_impl_dirbuffer buffer;
wf_impl_dirbuffer_init(&buffer);
if (NULL != result)
if (json_is_array(result))
{
if (json_is_array(result))
size_t const count = json_array_size(result);
for(size_t i = 0; i < count; i++)
{
bool buffer_full = false;
size_t const count = json_array_size(result);
for(size_t i = 0; (!buffer_full) && (i < count); i++)
json_t * entry =json_array_get(result, i);
if (json_is_object(entry))
{
json_t * entry =json_array_get(result, i);
if (json_is_object(entry))
json_t * name_holder = json_object_get(entry, "name");
json_t * inode_holder = json_object_get(entry, "inode");
if ((json_is_string(name_holder)) && (json_is_integer(inode_holder)))
{
char const * name = json_string_value(name_holder);
fuse_ino_t entry_inode = (fuse_ino_t) json_integer_value(inode_holder);
wf_impl_dirbuffer_add(context->request, &buffer, name, entry_inode);
}
else
{
json_t * name_holder = json_object_get(entry, "name");
json_t * inode_holder = json_object_get(entry, "inode");
if ((NULL != name_holder) && (json_is_string(name_holder)) &&
(NULL != inode_holder) && (json_is_integer(inode_holder)))
{
char const * name = json_string_value(name_holder);
fuse_ino_t entry_inode = (fuse_ino_t) json_integer_value(inode_holder);
wf_impl_dirbuffer_add(context->request, &buffer, name, entry_inode);
}
status = WF_BAD_FORMAT;
break;
}
}
else
{
status = WF_BAD_FORMAT;
break;
}
}
}
else if (WF_GOOD == status)
{
status = WF_BAD_FORMAT;
}
if (WF_GOOD == status)
{
@ -136,17 +141,17 @@ void wf_impl_operation_readdir (
off_t offset,
struct fuse_file_info * WF_UNUSED_PARAM(file_info))
{
struct wf_impl_operations_context * user_data = fuse_req_userdata(request);
struct wf_impl_jsonrpc_proxy * rpc = wf_impl_operations_context_get_proxy(user_data);
struct wf_impl_operation_context * user_data = fuse_req_userdata(request);
struct wf_jsonrpc_proxy * rpc = wf_impl_operation_context_get_proxy(user_data);
if (NULL != rpc)
{
struct wf_impl_operation_readdir_context * readdir_context = malloc(sizeof(struct wf_impl_operation_readdir_context));
readdir_context->request = request;
readdir_context->size = size;
readdir_context->offset = offset;
struct wf_impl_operation_readdir_context * readdir_context = malloc(sizeof(struct wf_impl_operation_readdir_context));
readdir_context->request = request;
readdir_context->size = size;
readdir_context->offset = offset;
wf_impl_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_readdir_finished, readdir_context, "readdir", "si", user_data->name, inode);
wf_jsonrpc_proxy_invoke(rpc, &wf_impl_operation_readdir_finished, readdir_context, "readdir", "si", user_data->name, inode);
}
else
{

@ -0,0 +1,35 @@
#ifndef WF_ADAPTER_IMPL_OPERATION_READDIR_H
#define WF_ADAPTER_IMPL_OPERATION_READDIR_H
#include "webfuse/adapter/impl/fuse_wrapper.h"
#include <jansson.h>
#ifdef __cplusplus
extern "C"
{
#endif
struct wf_impl_operation_readdir_context
{
fuse_req_t request;
size_t size;
off_t offset;
};
extern void wf_impl_operation_readdir (
fuse_req_t request,
fuse_ino_t inode,
size_t size,
off_t offset,
struct fuse_file_info *file_info);
extern void wf_impl_operation_readdir_finished(
void * user_data,
json_t const * result,
json_t const * error);
#ifdef __cplusplus
}
#endif
#endif

@ -1,18 +0,0 @@
#include "webfuse/adapter/impl/operations.h"
#include "webfuse/adapter/impl/session_manager.h"
#include "webfuse/adapter/impl/session.h"
#include <stddef.h>
struct wf_impl_jsonrpc_proxy * wf_impl_operations_context_get_proxy(
struct wf_impl_operations_context * context)
{
struct wf_impl_jsonrpc_proxy * proxy = NULL;
struct wf_impl_session * session = context->session;
if (NULL != session)
{
proxy = &session->rpc;
}
return proxy;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save