diff --git a/CMakeLists.txt b/CMakeLists.txt index ae4ee7c..48df128 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,81 +190,6 @@ 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) - -if(NOT WITHOUT_EXAMPLE) - -# libuserdb - -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) diff --git a/README.md b/README.md index fbaba22..716e079 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ 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) @@ -32,6 +33,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) diff --git a/example/daemon/main.c b/example/daemon/main.c deleted file mode 100644 index 2cde4ab..0000000 --- a/example/daemon/main.c +++ /dev/null @@ -1,196 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#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 \n" - "Websocket file system daemon\n" - "\n" - "Usage: webfused [m ] [-d ] [-p ]\n" - " [-c ] [-k ] [-P ]\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; -} - diff --git a/example/daemon/www/index.html b/example/daemon/www/index.html deleted file mode 100644 index 0cb0918..0000000 --- a/example/daemon/www/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - WebFuse Example - - - - - - -
-
-
Connection
-
-
-
- - - \ No newline at end of file diff --git a/example/daemon/www/js/.eslintrc.js b/example/daemon/www/js/.eslintrc.js deleted file mode 100644 index 9090e7d..0000000 --- a/example/daemon/www/js/.eslintrc.js +++ /dev/null @@ -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" - } -}; \ No newline at end of file diff --git a/example/daemon/www/js/connection_view.js b/example/daemon/www/js/connection_view.js deleted file mode 100644 index 31576ae..0000000 --- a/example/daemon/www/js/connection_view.js +++ /dev/null @@ -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"; - } - -} diff --git a/example/daemon/www/js/filesystem_provider.js b/example/daemon/www/js/filesystem_provider.js deleted file mode 100644 index 85ad287..0000000 --- a/example/daemon/www/js/filesystem_provider.js +++ /dev/null @@ -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); - } - } -} \ No newline at end of file diff --git a/example/daemon/www/js/package.json b/example/daemon/www/js/package.json deleted file mode 100644 index 6c553ef..0000000 --- a/example/daemon/www/js/package.json +++ /dev/null @@ -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" -} diff --git a/example/daemon/www/js/startup.js b/example/daemon/www/js/startup.js deleted file mode 100644 index 284d229..0000000 --- a/example/daemon/www/js/startup.js +++ /dev/null @@ -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; diff --git a/example/daemon/www/js/webfuse/bad_state.js b/example/daemon/www/js/webfuse/bad_state.js deleted file mode 100644 index fdb05d9..0000000 --- a/example/daemon/www/js/webfuse/bad_state.js +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/example/daemon/www/js/webfuse/client.js b/example/daemon/www/js/webfuse/client.js deleted file mode 100644 index 65d24f2..0000000 --- a/example/daemon/www/js/webfuse/client.js +++ /dev/null @@ -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); - } - } -} \ No newline at end of file diff --git a/example/daemon/www/js/webfuse/file_mode.js b/example/daemon/www/js/webfuse/file_mode.js deleted file mode 100644 index b81a1ea..0000000 --- a/example/daemon/www/js/webfuse/file_mode.js +++ /dev/null @@ -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; } -} \ No newline at end of file diff --git a/example/daemon/www/js/webfuse/provider.js b/example/daemon/www/js/webfuse/provider.js deleted file mode 100644 index b9c5dc2..0000000 --- a/example/daemon/www/js/webfuse/provider.js +++ /dev/null @@ -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); - } -} diff --git a/example/daemon/www/style/main.css b/example/daemon/www/style/main.css deleted file mode 100644 index 399bfd1..0000000 --- a/example/daemon/www/style/main.css +++ /dev/null @@ -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; -} - diff --git a/example/lib/userdb/include/userdb.h b/example/lib/userdb/include/userdb.h deleted file mode 100644 index cf133d0..0000000 --- a/example/lib/userdb/include/userdb.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef USERDB_H -#define USERDB_H - -#ifndef __cplusplus -#include -#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 \ No newline at end of file diff --git a/example/lib/userdb/src/userdb.c b/example/lib/userdb/src/userdb.c deleted file mode 100644 index 172742a..0000000 --- a/example/lib/userdb/src/userdb.c +++ /dev/null @@ -1,277 +0,0 @@ -#include "userdb.h" - -#include -#include -#include -#include - -#include -#include - -#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; -} \ No newline at end of file diff --git a/example/passwd/main.c b/example/passwd/main.c deleted file mode 100644 index 83862cc..0000000 --- a/example/passwd/main.c +++ /dev/null @@ -1,304 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - - -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 \n" - "Manage webfuse passwd file\n" - "\n" - "Usage: webfuse-passwd -f -c [-u ] [-p ] [-P ]\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 = -{ - "", - &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; -} \ No newline at end of file diff --git a/example/provider/main.c b/example/provider/main.c deleted file mode 100644 index 18fe42e..0000000 --- a/example/provider/main.c +++ /dev/null @@ -1,385 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#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 \n" - "Example for websocket file system provider\n" - "\n" - "Usage: webfuse-provider -u [-k ] [-c ]\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 = "", .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; -} \ No newline at end of file diff --git a/example/provider/static_filesystem.c b/example/provider/static_filesystem.c deleted file mode 100644 index 631274e..0000000 --- a/example/provider/static_filesystem.c +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include -#include -#include -#include - -#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 \n" - "Example of webfuse static filesystem provider\n" - "\n" - "Usage: static-filesystem-provider \n" - "\n" - "Arguments:\n" - "\t 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) && (!args.show_help)) - { - 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, "brummni/hello_world.txt", 0444, "Hello, World!\n"); - wfp_static_filesystem_add_text(fs, "brummni/hello_bob.txt", 0444, "Hello, Bob!\n"); - wfp_static_filesystem_add_text(fs, "brummni/hello_bob.txt", 0444, "Hello, Alice!\n"); - wfp_static_filesystem_add_text(fs, "bla/hello_world.txt", 0444, "Hello, World!\n"); - wfp_static_filesystem_add_text(fs, "foo.txt", 0444, "foo\n"); - wfp_static_filesystem_add_text(fs, "bar.txt", 0444, "bar\n"); - - 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; -}