From fd713e737d244240904234320a40ad9234711185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20S=C3=B6ntgen?= Date: Fri, 4 Jan 2019 13:28:10 +0100 Subject: [PATCH] Add FUSE implementation and dependencies Imported from the genode repository. Fixes #129. Issue genodelabs/genode#3104. --- include/fuse/fuse.h | 161 +++++ include/fuse/fuse_opt.h | 56 ++ include/fuse/fuse_private.h | 154 +++++ lib/import/import-libexfat.mk | 1 + lib/import/import-libext2fs.mk | 1 + lib/import/import-libfuse.mk | 1 + lib/import/import-libntfs-3g.mk | 1 + lib/mk/libc_fuse.mk | 7 + lib/mk/libc_fuse_exfat.mk | 15 + lib/mk/libc_fuse_ext2.mk | 25 + lib/mk/libc_fuse_ntfs-3g.mk | 20 + lib/mk/libexfat.mk | 17 + lib/mk/libext2fs.mk | 29 + lib/mk/libfuse.mk | 11 + lib/mk/libntfs-3g.mk | 17 + ports/exfat.hash | 1 + ports/exfat.port | 12 + ports/fuse-ext2.hash | 1 + ports/fuse-ext2.port | 16 + ports/ntfs-3g.hash | 1 + ports/ntfs-3g.port | 13 + run/libc_fuse_exfat.run | 6 + run/libc_fuse_ext2.run | 6 + run/libc_vfs_exfat_fuse_fs.run | 7 + run/libc_vfs_ext2_fuse_fs.run | 7 + run/libc_vfs_ntfs-3g_fuse_fs.run | 7 + src/lib/exfat/init.cc | 66 ++ src/lib/exfat/main.c.patch | 26 + src/lib/fuse-ext2/config.h | 373 +++++++++++ src/lib/fuse-ext2/init.cc | 104 +++ src/lib/fuse-ext2/patches/bitops.h.patch | 10 + src/lib/fuse-ext2/patches/closefs.c.patch | 21 + src/lib/fuse-ext2/patches/com_err.c.patch | 10 + .../fuse-ext2/patches/error_message.c.patch | 10 + src/lib/fuse-ext2/patches/ext2fs.h.patch | 14 + src/lib/fuse-ext2/patches/fuse-ext2.c.patch | 23 + src/lib/fuse-ext2/patches/fuse-ext2.h.patch | 19 + .../fuse-ext2/patches/gen_bitmap64.c.patch | 7 + src/lib/fuse-ext2/patches/icount.c.patch | 10 + src/lib/fuse-ext2/patches/init_et.c.patch | 10 + src/lib/fuse-ext2/patches/op_access.c.patch | 10 + src/lib/fuse-ext2/patches/op_statfs.c.patch | 14 + src/lib/fuse-ext2/patches/res_gdt.c.patch | 10 + src/lib/fuse-ext2/patches/rw_bitmaps.c.patch | 10 + src/lib/fuse-ext2/patches/tdb.c.patch | 16 + src/lib/fuse-ext2/patches/test_io.c.patch | 10 + src/lib/fuse-ext2/patches/unix_io.c.patch | 10 + src/lib/fuse/fuse.cc | 299 +++++++++ src/lib/libc_fuse/plugin.cc | 534 ++++++++++++++++ src/lib/ntfs-3g/config.h | 372 +++++++++++ src/lib/ntfs-3g/init.cc | 112 ++++ src/lib/ntfs-3g/ntfs-3g.c.patch | 53 ++ src/server/fuse_fs/README | 26 + src/server/fuse_fs/directory.h | 293 +++++++++ src/server/fuse_fs/exfat/target.mk | 18 + src/server/fuse_fs/ext2/target.mk | 34 + src/server/fuse_fs/file.h | 159 +++++ src/server/fuse_fs/fuse_fs_main.cc | 595 ++++++++++++++++++ src/server/fuse_fs/mode_util.h | 35 ++ src/server/fuse_fs/node.h | 62 ++ src/server/fuse_fs/ntfs-3g/target.mk | 23 + src/server/fuse_fs/open_node.h | 95 +++ src/server/fuse_fs/symlink.h | 93 +++ src/server/fuse_fs/util.h | 103 +++ src/test/libc_fuse_exfat/target.mk | 7 + src/test/libc_fuse_ext2/target.mk | 7 + src/test/libc_fuse_ntfs-3g/target.mk | 7 + 67 files changed, 4303 insertions(+) create mode 100644 include/fuse/fuse.h create mode 100644 include/fuse/fuse_opt.h create mode 100644 include/fuse/fuse_private.h create mode 100644 lib/import/import-libexfat.mk create mode 100644 lib/import/import-libext2fs.mk create mode 100644 lib/import/import-libfuse.mk create mode 100644 lib/import/import-libntfs-3g.mk create mode 100644 lib/mk/libc_fuse.mk create mode 100644 lib/mk/libc_fuse_exfat.mk create mode 100644 lib/mk/libc_fuse_ext2.mk create mode 100644 lib/mk/libc_fuse_ntfs-3g.mk create mode 100644 lib/mk/libexfat.mk create mode 100644 lib/mk/libext2fs.mk create mode 100644 lib/mk/libfuse.mk create mode 100644 lib/mk/libntfs-3g.mk create mode 100644 ports/exfat.hash create mode 100644 ports/exfat.port create mode 100644 ports/fuse-ext2.hash create mode 100644 ports/fuse-ext2.port create mode 100644 ports/ntfs-3g.hash create mode 100644 ports/ntfs-3g.port create mode 100644 run/libc_fuse_exfat.run create mode 100644 run/libc_fuse_ext2.run create mode 100644 run/libc_vfs_exfat_fuse_fs.run create mode 100644 run/libc_vfs_ext2_fuse_fs.run create mode 100644 run/libc_vfs_ntfs-3g_fuse_fs.run create mode 100644 src/lib/exfat/init.cc create mode 100644 src/lib/exfat/main.c.patch create mode 100644 src/lib/fuse-ext2/config.h create mode 100644 src/lib/fuse-ext2/init.cc create mode 100644 src/lib/fuse-ext2/patches/bitops.h.patch create mode 100644 src/lib/fuse-ext2/patches/closefs.c.patch create mode 100644 src/lib/fuse-ext2/patches/com_err.c.patch create mode 100644 src/lib/fuse-ext2/patches/error_message.c.patch create mode 100644 src/lib/fuse-ext2/patches/ext2fs.h.patch create mode 100644 src/lib/fuse-ext2/patches/fuse-ext2.c.patch create mode 100644 src/lib/fuse-ext2/patches/fuse-ext2.h.patch create mode 100644 src/lib/fuse-ext2/patches/gen_bitmap64.c.patch create mode 100644 src/lib/fuse-ext2/patches/icount.c.patch create mode 100644 src/lib/fuse-ext2/patches/init_et.c.patch create mode 100644 src/lib/fuse-ext2/patches/op_access.c.patch create mode 100644 src/lib/fuse-ext2/patches/op_statfs.c.patch create mode 100644 src/lib/fuse-ext2/patches/res_gdt.c.patch create mode 100644 src/lib/fuse-ext2/patches/rw_bitmaps.c.patch create mode 100644 src/lib/fuse-ext2/patches/tdb.c.patch create mode 100644 src/lib/fuse-ext2/patches/test_io.c.patch create mode 100644 src/lib/fuse-ext2/patches/unix_io.c.patch create mode 100644 src/lib/fuse/fuse.cc create mode 100644 src/lib/libc_fuse/plugin.cc create mode 100644 src/lib/ntfs-3g/config.h create mode 100644 src/lib/ntfs-3g/init.cc create mode 100644 src/lib/ntfs-3g/ntfs-3g.c.patch create mode 100644 src/server/fuse_fs/README create mode 100644 src/server/fuse_fs/directory.h create mode 100644 src/server/fuse_fs/exfat/target.mk create mode 100644 src/server/fuse_fs/ext2/target.mk create mode 100644 src/server/fuse_fs/file.h create mode 100644 src/server/fuse_fs/fuse_fs_main.cc create mode 100644 src/server/fuse_fs/mode_util.h create mode 100644 src/server/fuse_fs/node.h create mode 100644 src/server/fuse_fs/ntfs-3g/target.mk create mode 100644 src/server/fuse_fs/open_node.h create mode 100644 src/server/fuse_fs/symlink.h create mode 100644 src/server/fuse_fs/util.h create mode 100644 src/test/libc_fuse_exfat/target.mk create mode 100644 src/test/libc_fuse_ext2/target.mk create mode 100644 src/test/libc_fuse_ntfs-3g/target.mk diff --git a/include/fuse/fuse.h b/include/fuse/fuse.h new file mode 100644 index 0000000..137e19e --- /dev/null +++ b/include/fuse/fuse.h @@ -0,0 +1,161 @@ +/* + * \brief libfuse re-implementation public API + * \author Josef Soentgen + * \date 2013-11-07 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__FUSE_H_ +#define _INCLUDE__FUSE_H_ + +/* libc includes */ +#include +#include +#include +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef FUSE_USE_VERSION +#define FUSE_USE_VERSION 26 +#endif + +#if FUSE_USE_VERSION >= 26 +#define FUSE_VERSION 26 +#else +#error "No support for FUSE_VERSION < 26" +#endif + +void fuse_genode(const char*); + +#include "fuse_opt.h" + +struct fuse_chan; +struct fuse_args; +struct fuse_session; + +struct fuse_file_info { + int32_t flags; /* open(2) flags */ + uint32_t fh_old; /* old file handle */ + int32_t writepage; + uint32_t direct_io:1; + uint32_t keep_cache:1; + uint32_t flush:1; + uint32_t nonseekable:1; + uint32_t __padd:27; + uint32_t flock_release : 1; + uint64_t fh; /* file handle */ + uint64_t lock_owner; +}; + +struct fuse_conn_info { + uint32_t proto_major; + uint32_t proto_minor; + uint32_t async_read; + uint32_t max_write; + uint32_t max_readahead; + uint32_t capable; + uint32_t want; + uint32_t max_background; + uint32_t congestion_threshold; + uint32_t reserved[23]; +}; + +struct fuse_context { + struct fuse *fuse; + uid_t uid; + gid_t gid; + pid_t pid; + void *private_data; + mode_t umask; +}; + +typedef ino_t fuse_ino_t; +typedef int (*fuse_fill_dir_t)(void *, const char *, const struct stat *, off_t); + + + +typedef int (*fuse_dirfil_t)(void *, const char *, int, ino_t); + +/* only operations available in 2.6 */ +struct fuse_operations { + int (*getattr)(const char *, struct stat *); + int (*readlink)(const char *, char *, size_t); + int (*getdir)(const char *, void *, fuse_dirfil_t); + int (*mknod)(const char *, mode_t, dev_t); + int (*mkdir)(const char *, mode_t); + int (*unlink)(const char *); + int (*rmdir)(const char *); + int (*symlink)(const char *, const char *); + int (*rename)(const char *, const char *); + int (*link)(const char *, const char *); + int (*chmod)(const char *, mode_t); + int (*chown)(const char *, uid_t, gid_t); + int (*truncate)(const char *, off_t); + int (*utime)(const char *, struct utimbuf *); + int (*open)(const char *, struct fuse_file_info *); + int (*read)(const char *, char *, size_t, off_t, + struct fuse_file_info *); + int (*write)(const char *, const char *, size_t, off_t, + struct fuse_file_info *); + int (*statfs)(const char *, struct statvfs *); + int (*flush)(const char *, struct fuse_file_info *); + int (*release)(const char *, struct fuse_file_info *); + int (*fsync)(const char *, int, struct fuse_file_info *); + int (*setxattr)(const char *, const char *, const char *, size_t, + int); + int (*getxattr)(const char *, const char *, char *, size_t); + int (*listxattr)(const char *, char *, size_t); + int (*removexattr)(const char *, const char *); + int (*opendir)(const char *, struct fuse_file_info *); + int (*readdir)(const char *, void *, fuse_fill_dir_t, off_t, + struct fuse_file_info *); + int (*releasedir)(const char *, struct fuse_file_info *); + int (*fsyncdir)(const char *, int, struct fuse_file_info *); + void *(*init)(struct fuse_conn_info *); + void (*destroy)(void *); + int (*access)(const char *, int); + int (*create)(const char *, mode_t, struct fuse_file_info *); + int (*ftruncate)(const char *, off_t, struct fuse_file_info *); + int (*fgetattr)(const char *, struct stat *, struct fuse_file_info *); + int (*lock)(const char *, struct fuse_file_info *, int, struct flock *); + int (*utimens)(const char *, const struct timespec *); + int (*bmap)(const char *, size_t , uint64_t *); +}; + +/* API */ +int fuse_version(void); +struct fuse *fuse_new(struct fuse_chan *, struct fuse_args *, + const struct fuse_operations *, size_t, void *); +void fuse_destroy(struct fuse *); +void fuse_exit(struct fuse *f); +struct fuse_session *fuse_get_session(struct fuse *); +struct fuse_context *fuse_get_context(void); +int fuse_loop(struct fuse *); +int fuse_loop_mt(struct fuse *); +int fuse_main(int, char **, const struct fuse_operations *, void *); +struct fuse_chan *fuse_mount(const char *, struct fuse_args *); +int fuse_parse_cmdline(struct fuse_args *, char **, int *, int *); +void fuse_remove_signal_handlers(struct fuse_session *); +int fuse_set_signal_handlers(struct fuse_session *); +int fuse_chan_fd(struct fuse_chan *); +int fuse_daemonize(int); +int fuse_is_lib_option(const char *); +void fuse_teardown(struct fuse *, char *); +void fuse_unmount(const char *, struct fuse_chan *); + +#ifdef __cplusplus +} +#endif + +#endif /* _INCLUDE__FUSE_H_ */ diff --git a/include/fuse/fuse_opt.h b/include/fuse/fuse_opt.h new file mode 100644 index 0000000..7b8528a --- /dev/null +++ b/include/fuse/fuse_opt.h @@ -0,0 +1,56 @@ +/* + * \brief libfuse public API + * \author Josef Soentgen + * \date 2013-11-07 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _FUSE_OPT_H_ +#define _FUSE_OPT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct fuse_opt { + const char *templ; + unsigned long off; + int val; +}; + +struct fuse_args { + int argc; + char **argv; + int allocated; +}; + +typedef int (*fuse_opt_proc_t)(void *, const char *, int, struct fuse_args *); +int fuse_opt_add_arg(struct fuse_args *, const char *); +int fuse_opt_insert_arg(struct fuse_args *, int, const char *); +void fuse_opt_free_args(struct fuse_args *); +int fuse_opt_add_opt(char **, const char *); +int fuse_opt_add_opt_escaped(char **, const char *); +int fuse_opt_match(const struct fuse_opt *, const char *); +int fuse_opt_parse(struct fuse_args *, void *, struct fuse_opt *, + fuse_opt_proc_t); + +#define FUSE_ARGS_INIT(ac, av) { ac, av, 0 } + +#define FUSE_OPT_KEY(t, k) { t, -1, k } +#define FUSE_OPT_END { NULL, 0, 0 } +#define FUSE_OPT_KEY_OPT -1 +#define FUSE_OPT_KEY_NONOPT -2 +#define FUSE_OPT_KEY_KEEP -3 +#define FUSE_OPT_KEY_DISCARD -4 + +#ifdef __cplusplus +} +#endif + +#endif /* _FUSE_OPT_H_ */ diff --git a/include/fuse/fuse_private.h b/include/fuse/fuse_private.h new file mode 100644 index 0000000..885eca1 --- /dev/null +++ b/include/fuse/fuse_private.h @@ -0,0 +1,154 @@ +/* + * \brief libfuse private API + * \author Josef Soentgen + * \date 2013-11-07 + * */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__FUSE_PRIVATE_H_ +#define _INCLUDE__FUSE_PRIVATE_H_ + +#include "fuse.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct fuse_dirhandle; +struct fuse_args; + +struct fuse_session { + void *args; +}; + +struct fuse_chan { + char *dir; + struct fuse_args *args; +}; + +struct fuse_config { + uid_t uid; + gid_t gid; + pid_t pid; + mode_t umask; + int set_mode; + int set_uid; + int set_gid; +}; + +typedef struct fuse_dirhandle { + fuse_fill_dir_t filler; + void *buf; + size_t size; + off_t offset; +} *fuse_dirh_t; + + +struct fuse { + struct fuse_chan *fc; + struct fuse_operations op; + struct fuse_args *args; + + struct fuse_config conf; + struct fuse_session se; + + fuse_fill_dir_t filler; + + void *userdata; + + /* Block_session info */ + uint32_t block_size; + uint64_t block_count; +}; + +#ifdef __cplusplus +} +#endif + +namespace Fuse { + + struct fuse* fuse(); + + bool initialized(); + + /** + * Initialize the file system + * + * Mount the medium containg the file system, e.g. by + * using a Block_session connection, and call the file system + * init function as well as initialize needed fuse structures. + */ + bool init_fs(); + + /** + * Deinitialize the file system + * + * Unmount the medium, call the file system cleanup function + * and free all fuse structures. + */ + void deinit_fs(); + + /** + * Synchronize the file system + * + * Request the file system to flush all internal caches + * to disk. + */ + void sync_fs(); + + /** + * FUSE File system implementation supports symlinks + */ + bool support_symlinks(); + + /* list of FUSE operations as of version 2.6 */ + enum Fuse_operations { + FUSE_OP_GETATTR = 0, + FUSE_OP_READLINK = 1, + FUSE_OP_GETDIR = 2, + FUSE_OP_MKNOD = 3, + FUSE_OP_MKDIR = 4, + FUSE_OP_UNLINK = 5, + FUSE_OP_RMDIR = 6, + FUSE_OP_SYMLINK = 7, + FUSE_OP_RENAME = 8, + FUSE_OP_LINK = 9, + FUSE_OP_CHMOD = 10, + FUSE_OP_CHOWN = 11, + FUSE_OP_TRUNCATE = 12, + FUSE_OP_UTIME = 13, + FUSE_OP_OPEN = 14, + FUSE_OP_READ = 15, + FUSE_OP_WRITE = 16, + FUSE_OP_STATFS = 17, + FUSE_OP_FLUSH = 18, + FUSE_OP_RELEASE = 19, + FUSE_OP_FSYNC = 20, + FUSE_OP_SETXATTR = 21, + FUSE_OP_GETXATTR = 22, + FUSE_OP_LISTXATTR = 23, + FUSE_OP_REMOVEXATTR = 24, + FUSE_OP_OPENDIR = 25, + FUSE_OP_READDIR = 26, + FUSE_OP_RELEASEDIR = 27, + FUSE_OP_FSYNCDIR = 28, + FUSE_OP_INIT = 29, + FUSE_OP_DESTROY = 30, + FUSE_OP_ACCESS = 31, + FUSE_OP_CREATE = 32, + FUSE_OP_FTRUNCATE = 33, + FUSE_OP_FGETATTR = 34, + FUSE_OP_LOCK = 35, + FUSE_OP_UTIMENS = 36, + FUSE_OP_BMAP = 37, + FUSE_OP_MAX = 38, + }; +} + +#endif /* _INCLUDE__FUSE_PRIVATE_ */ diff --git a/lib/import/import-libexfat.mk b/lib/import/import-libexfat.mk new file mode 100644 index 0000000..331f6d1 --- /dev/null +++ b/lib/import/import-libexfat.mk @@ -0,0 +1 @@ +INC_DIR += $(call select_from_ports,exfat)/include diff --git a/lib/import/import-libext2fs.mk b/lib/import/import-libext2fs.mk new file mode 100644 index 0000000..49c3fd3 --- /dev/null +++ b/lib/import/import-libext2fs.mk @@ -0,0 +1 @@ +INC_DIR += $(call select_from_ports,fuse-ext2)/include/fuse-ext2 diff --git a/lib/import/import-libfuse.mk b/lib/import/import-libfuse.mk new file mode 100644 index 0000000..132cf5b --- /dev/null +++ b/lib/import/import-libfuse.mk @@ -0,0 +1 @@ +REP_INC_DIR += include/fuse diff --git a/lib/import/import-libntfs-3g.mk b/lib/import/import-libntfs-3g.mk new file mode 100644 index 0000000..9aabfb9 --- /dev/null +++ b/lib/import/import-libntfs-3g.mk @@ -0,0 +1 @@ +INC_DIR += $(call select_from_ports,ntfs-3g)/include/ntfs-3g diff --git a/lib/mk/libc_fuse.mk b/lib/mk/libc_fuse.mk new file mode 100644 index 0000000..822f741 --- /dev/null +++ b/lib/mk/libc_fuse.mk @@ -0,0 +1,7 @@ +LIBS = libc libfuse + +SRC_CC = plugin.cc + +vpath %.cc $(REP_DIR)/src/lib/libc_fuse + +CC_CXX_WARN_STRICT = diff --git a/lib/mk/libc_fuse_exfat.mk b/lib/mk/libc_fuse_exfat.mk new file mode 100644 index 0000000..635cd49 --- /dev/null +++ b/lib/mk/libc_fuse_exfat.mk @@ -0,0 +1,15 @@ +REQUIRES = conversion_to_vfs_plugin + +EXFAT_DIR := $(call select_from_ports,exfat)/src/lib/exfat + +SRC_C = $(notdir $(EXFAT_DIR)/fuse/main.c) +SRC_CC = init.cc + +LIBS = libc libc_fuse libfuse libexfat + +vpath %.c $(EXFAT_DIR)/fuse +vpath %.cc $(REP_DIR)/src/lib/exfat + +SHARED_LIB = yes + +CC_CXX_WARN_STRICT = diff --git a/lib/mk/libc_fuse_ext2.mk b/lib/mk/libc_fuse_ext2.mk new file mode 100644 index 0000000..2ccd451 --- /dev/null +++ b/lib/mk/libc_fuse_ext2.mk @@ -0,0 +1,25 @@ +REQUIRES = conversion_to_vfs_plugin + +FUSE_EXT2_PORT_DIR := $(call select_from_ports,fuse-ext2) +FUSE_EXT2_DIR := $(FUSE_EXT2_PORT_DIR)/src/lib/fuse-ext2/fuse-ext2 + +FILTER_OUT = fuse-ext2.probe.c fuse-ext2.wait.c +SRC_C = $(filter-out $(FILTER_OUT), $(notdir $(wildcard $(FUSE_EXT2_DIR)/*.c))) +SRC_CC = init.cc + +LIBS = libc libc_fuse libfuse libext2fs + +CC_OPT = -DHAVE_CONFIG_H -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 + +CC_CXX_OPT +=-fpermissive + +INC_DIR += $(REP_DIR)/src/lib/fuse-ext2 \ + $(FUSE_EXT2_DIR) \ + $(FUSE_EXT2_PORT_DIR)/include/fuse-ext2 + +vpath %.c $(FUSE_EXT2_DIR) +vpath %.cc $(REP_DIR)/src/lib/fuse-ext2 + +SHARED_LIB = yes + +CC_CXX_WARN_STRICT = diff --git a/lib/mk/libc_fuse_ntfs-3g.mk b/lib/mk/libc_fuse_ntfs-3g.mk new file mode 100644 index 0000000..c659c50 --- /dev/null +++ b/lib/mk/libc_fuse_ntfs-3g.mk @@ -0,0 +1,20 @@ +REQUIRES = conversion_to_vfs_plugin + +NTFS_3G_DIR := $(call select_from_ports,ntfs-3g)/src/lib/ntfs-3g + +SRC_C = ntfs-3g.c ntfs-3g_common.c +SRC_CC = init.cc + +LIBS = libc libc_fuse libfuse libntfs-3g + +CC_OPT = -DHAVE_TIMESPEC -DHAVE_CONFIG_H -DRECORD_LOCKING_NOT_IMPLEMENTED + +INC_DIR += $(REP_DIR)/src/lib/ntfs-3g \ + $(NTFS_3G_DIR)/src + +vpath %.c $(NTFS_3G_DIR)/src +vpath %.cc $(REP_DIR)/src/lib/ntfs-3g + +SHARED_LIB = yes + +CC_CXX_WARN_STRICT = diff --git a/lib/mk/libexfat.mk b/lib/mk/libexfat.mk new file mode 100644 index 0000000..bab04d8 --- /dev/null +++ b/lib/mk/libexfat.mk @@ -0,0 +1,17 @@ +EXFAT_DIR = $(call select_from_ports,exfat)/src/lib/exfat + +#FILTER_OUT = win32_io.c +#SRC_C = $(filter-out $(FILTER_OUT),$(notdir $(wildcard $(EXFAT_DIR)/libexfat/*.c))) + +SRC_C = $(notdir $(wildcard $(EXFAT_DIR)/libexfat/*.c)) + +INC_DIR += $(REP_DIR)/include/exfat \ + $(EXFAT_DIR)/libexfat + +#CC_OPT += -DHAVE_CONFIG_H -DRECORD_LOCKING_NOT_IMPLEMENTED + +LIBS += libc + +vpath %.c $(EXFAT_DIR)/libexfat + +CC_CXX_WARN_STRICT = diff --git a/lib/mk/libext2fs.mk b/lib/mk/libext2fs.mk new file mode 100644 index 0000000..40b6916 --- /dev/null +++ b/lib/mk/libext2fs.mk @@ -0,0 +1,29 @@ +FUSE_EXT2_PORT_DIR := $(call select_from_ports,fuse-ext2) +FUSE_EXT2_DIR = $(FUSE_EXT2_PORT_DIR)/src/lib/fuse-ext2 +E2FSPROGS_DIR = $(FUSE_EXT2_DIR)/e2fsprogs-1.41.12.newgit +EXT2FS_DIR = $(E2FSPROGS_DIR)/ext2fs +ET_DIR = $(E2FSPROGS_DIR)/et + +FILTER_OUT = bmove.c dosio.c irel_ma.c nt_io.c tdbtool.c +SRC_C = $(filter-out $(FILTER_OUT), $(notdir $(wildcard $(EXT2FS_DIR)/*.c))) +SRC_C += $(notdir $(wildcard $(ET_DIR)/*.c)) + +INC_DIR += $(REP_DIR)/include/fuse-ext2 \ + $(REP_DIR)/src/lib/fuse-ext2 \ + $(FUSE_EXT2_PORT_DIR)/include/fuse-ext2 \ + $(ET_DIR) + +CC_OPT += -DHAVE_CONFIG_H -D__BSD_VISIBLE -DENABLE_DEBUG + +CC_OPT += -Wno-unused-function -Wno-unused-variable \ + -Wno-unused-but-set-variable -Wno-cpp \ + -Wno-maybe-uninitialized -Wno-uninitialized + +CC_C_OPT += -std=gnu89 + +LIBS += libc + +vpath %.c $(EXT2FS_DIR) +vpath %.c $(ET_DIR) + +CC_CXX_WARN_STRICT = diff --git a/lib/mk/libfuse.mk b/lib/mk/libfuse.mk new file mode 100644 index 0000000..898ba3b --- /dev/null +++ b/lib/mk/libfuse.mk @@ -0,0 +1,11 @@ +SRC_CC = fuse.cc + +INC_DIR += $(REP_DIR)/include/fuse + +LIBS = libc + +CC_OPT += -fpermissive + +vpath %.cc $(REP_DIR)/src/lib/fuse + +CC_CXX_WARN_STRICT = diff --git a/lib/mk/libntfs-3g.mk b/lib/mk/libntfs-3g.mk new file mode 100644 index 0000000..044b15e --- /dev/null +++ b/lib/mk/libntfs-3g.mk @@ -0,0 +1,17 @@ +NTFS_3G_PORT_DIR := $(call select_from_ports,ntfs-3g) +NTFS_3G_DIR := $(NTFS_3G_PORT_DIR)/src/lib/ntfs-3g + +FILTER_OUT = win32_io.c +SRC_C = $(filter-out $(FILTER_OUT),$(notdir $(wildcard $(NTFS_3G_DIR)/libntfs-3g/*.c))) + +INC_DIR += $(REP_DIR)/include/ntfs-3g \ + $(REP_DIR)/src/lib/ntfs-3g \ + $(NTFS_3G_PORT_DIR)/include/ntfs-3g + +CC_OPT += -DHAVE_CONFIG_H -DRECORD_LOCKING_NOT_IMPLEMENTED -DDEBUG + +LIBS += libc + +vpath %.c $(NTFS_3G_DIR)/libntfs-3g + +CC_CXX_WARN_STRICT = diff --git a/ports/exfat.hash b/ports/exfat.hash new file mode 100644 index 0000000..3a323a3 --- /dev/null +++ b/ports/exfat.hash @@ -0,0 +1 @@ +97a451ebdb6d3071b753d6fcd9e5aa6a0eda665f diff --git a/ports/exfat.port b/ports/exfat.port new file mode 100644 index 0000000..163fbef --- /dev/null +++ b/ports/exfat.port @@ -0,0 +1,12 @@ +LICENSE := GPLv3 +VERSION := 1.0.1 +DOWNLOADS := exfat.archive + +URL(exfat) := https://genode.org/files/fuse-exfat-$(VERSION).tar.gz +SHA(exfat) := 12ac1ba1b7d4343bef64e7898176705a41cfe3b5a7a179e28549d242e2854758 +DIR(exfat) := src/lib/exfat + +PATCHES := src/lib/exfat/main.c.patch + +DIRS := include +DIR_CONTENT(include) := src/lib/exfat/libexfat/*.h diff --git a/ports/fuse-ext2.hash b/ports/fuse-ext2.hash new file mode 100644 index 0000000..d606083 --- /dev/null +++ b/ports/fuse-ext2.hash @@ -0,0 +1 @@ +867fc9cb8f828f6463871d5db396b8cda9d7b5b5 diff --git a/ports/fuse-ext2.port b/ports/fuse-ext2.port new file mode 100644 index 0000000..c3d3bd0 --- /dev/null +++ b/ports/fuse-ext2.port @@ -0,0 +1,16 @@ +LICENSE := GPLv2 +VERSION := svn-220 +DOWNLOADS := fuse-ext2.svn + +URL(fuse-ext2) := http://svn.code.sf.net/p/fuse-ext2/code/branch/renzo +REV(fuse-ext2) := 220 +DIR(fuse-ext2) := src/lib/fuse-ext2 + +PATCHES := src/lib/fuse-ext2/patches/*.patch + +DIRS := $(addprefix include/fuse-ext2/,e2p et ext2fs) +e2fs_dir := src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit + +DIR_CONTENT(include/fuse-ext2/e2p) := $(e2fs_dir)/e2p/*.h +DIR_CONTENT(include/fuse-ext2/et) := $(e2fs_dir)/et/*.h +DIR_CONTENT(include/fuse-ext2/ext2fs) := $(e2fs_dir)/ext2fs/*.h diff --git a/ports/ntfs-3g.hash b/ports/ntfs-3g.hash new file mode 100644 index 0000000..a7605c3 --- /dev/null +++ b/ports/ntfs-3g.hash @@ -0,0 +1 @@ +436966b79dec7c24b28b6bbfa5c356b4f5e3846e diff --git a/ports/ntfs-3g.port b/ports/ntfs-3g.port new file mode 100644 index 0000000..1d6eb1d --- /dev/null +++ b/ports/ntfs-3g.port @@ -0,0 +1,13 @@ +LICENSE := GPLv2 +VERSION := 2013.1.13 +DOWNLOADS := ntfs-3g.archive + +URL(ntfs-3g) := http://tuxera.com/opensource/ntfs-3g_ntfsprogs-$(VERSION).tgz +SHA(ntfs-3g) := 4b383f0074a3ab7683339d1f18222b107aaeb4983db119292c43c2b275cefb27 +DIR(ntfs-3g) := src/lib/ntfs-3g + +PATCHES := src/lib/ntfs-3g/*.patch + +DIRS := include/ntfs-3g +DIR_CONTENT(include/ntfs-3g) := src/lib/ntfs-3g/include/ntfs-3g/*.h + diff --git a/run/libc_fuse_exfat.run b/run/libc_fuse_exfat.run new file mode 100644 index 0000000..64c5a8c --- /dev/null +++ b/run/libc_fuse_exfat.run @@ -0,0 +1,6 @@ +set mkfs_cmd mkfs.exfat +set mkfs_opts "" +set filesystem fuse_exfat +set libc_dev_blkdev {} + +source ${genode_dir}/repos/libports/run/libc_filesystem_test.inc diff --git a/run/libc_fuse_ext2.run b/run/libc_fuse_ext2.run new file mode 100644 index 0000000..7f6306f --- /dev/null +++ b/run/libc_fuse_ext2.run @@ -0,0 +1,6 @@ +set mkfs_cmd mkfs.ext2 +set mkfs_opts "-F" +set filesystem fuse_ext2 +set libc_dev_blkdev {} + +source ${genode_dir}/repos/libports/run/libc_filesystem_test.inc diff --git a/run/libc_vfs_exfat_fuse_fs.run b/run/libc_vfs_exfat_fuse_fs.run new file mode 100644 index 0000000..789d042 --- /dev/null +++ b/run/libc_vfs_exfat_fuse_fs.run @@ -0,0 +1,7 @@ +set build_component server/fuse_fs/exfat +set binary exfat_fuse_fs +set mkfs_cmd mkfs.exfat +set mkfs_opts "" +set vfs_dev_blkdev {} + +source ${genode_dir}/repos/libports/run/libc_vfs_fs_test.inc diff --git a/run/libc_vfs_ext2_fuse_fs.run b/run/libc_vfs_ext2_fuse_fs.run new file mode 100644 index 0000000..eb61360 --- /dev/null +++ b/run/libc_vfs_ext2_fuse_fs.run @@ -0,0 +1,7 @@ +set build_component server/fuse_fs/ext2 +set binary ext2_fuse_fs +set mkfs_cmd mkfs.ext2 +set mkfs_opts "-F" +set vfs_dev_blkdev {} + +source ${genode_dir}/repos/libports/run/libc_vfs_fs_test.inc diff --git a/run/libc_vfs_ntfs-3g_fuse_fs.run b/run/libc_vfs_ntfs-3g_fuse_fs.run new file mode 100644 index 0000000..b2268e3 --- /dev/null +++ b/run/libc_vfs_ntfs-3g_fuse_fs.run @@ -0,0 +1,7 @@ +set build_component server/fuse_fs/ntfs-3g +set binary ntfs-3g_fuse_fs +set mkfs_cmd mkfs.ntfs +set mkfs_opts "" +set vfs_dev_blkdev {} + +source ${genode_dir}/repos/libports/run/libc_vfs_fs_test.inc diff --git a/src/lib/exfat/init.cc b/src/lib/exfat/init.cc new file mode 100644 index 0000000..f5d76d5 --- /dev/null +++ b/src/lib/exfat/init.cc @@ -0,0 +1,66 @@ +/* + * \brief libc_fuse_exfat + * \author Josef Soentgen + * \date 2013-11-11 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include + +#include + +extern "C" { + +#include + +extern struct fuse_operations fuse_exfat_ops; + +struct fuse_chan *fc; +struct fuse *fh; + +struct exfat ef; + +} + + +bool Fuse::init_fs(void) +{ + Genode::log("libc_fuse_exfat: try to mount /dev/blkdev..."); + + int err = exfat_mount(&ef, "/dev/blkdev", ""); + if (err) { + Genode::error("libc_fuse_exfat: could not mount /dev/blkdev"); + return false; + } + + fh = fuse_new(fc, NULL, &fuse_exfat_ops, sizeof (struct fuse_operations), NULL); + if (fh == 0) { + Genode::error("libc_fuse_exfat: fuse_new() failed"); + return false; + } + + return true; +} + + +void Fuse::deinit_fs(void) +{ + Genode::log("libc_fuse_exfat: umount /dev/blkdev..."); + exfat_unmount(&ef); +} + + +void Fuse::sync_fs(void) { } + + +bool Fuse::support_symlinks(void) +{ + return false; +} diff --git a/src/lib/exfat/main.c.patch b/src/lib/exfat/main.c.patch new file mode 100644 index 0000000..dc49583 --- /dev/null +++ b/src/lib/exfat/main.c.patch @@ -0,0 +1,26 @@ +Make fuse_operation struct globally accessible and comment-out +main() function. + ++++ src/lib/exfat/fuse/main.c +@@ -296,7 +296,7 @@ + exit(1); + } + +-static struct fuse_operations fuse_exfat_ops = ++struct fuse_operations fuse_exfat_ops = + { + .getattr = fuse_exfat_getattr, + .truncate = fuse_exfat_truncate, +@@ -403,6 +403,7 @@ + return options; + } + ++#if 0 + int main(int argc, char* argv[]) + { + struct fuse_args mount_args = FUSE_ARGS_INIT(0, NULL); +@@ -550,3 +551,4 @@ + fuse_destroy(fh); + return 0; + } ++#endif diff --git a/src/lib/fuse-ext2/config.h b/src/lib/fuse-ext2/config.h new file mode 100644 index 0000000..b36f29a --- /dev/null +++ b/src/lib/fuse-ext2/config.h @@ -0,0 +1,373 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if the `closedir' function returns void instead of `int'. */ +/* #undef CLOSEDIR_VOID */ + +/* Define to 1 if you want 'debug' support. */ +#define ENABLE_DEBUG 1 + +/* Define to 1 if you want 'swapfs' support. */ +#define ENABLE_SWAPFS 1 + +/* Version of FUSE interface */ +#define FUSE_USE_VERSION 26 + +/* Define to 1 if your system has a working `chown' function. */ +/* #undef HAVE_CHOWN */ + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#define HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `ftruncate' function. */ +#define HAVE_FTRUNCATE 1 + +/* Define to 1 if you have the `getdtablesize' function. */ +/* #undef HAVE_GETDTABLESIZE */ + +/* Define to 1 if you have the `getmntent' function. */ +#define HAVE_GETMNTENT 1 + +/* Define to 1 if you have the `getmntinfo' function. */ +/* #undef HAVE_GETMNTINFO */ + +/* Define to 1 if you have the header file. */ +#define HAVE_GETOPT_H 1 + +/* Define to 1 if you have the `getpagesize' function. */ +#define HAVE_GETPAGESIZE 1 + +/* Define to 1 if you have the `hasmntopt' function. */ +/* #undef HAVE_HASMNTOPT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `ext2fs' library (-lext2fs). */ +#define HAVE_LIBEXT2FS 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_FD_H */ + +/* Define to 1 if you have the `llseek' function. */ +/* #undef HAVE_LLSEEK */ + +/* Define to 1 if you have the `llseek' prototype. */ +/* #undef HAVE_LLSEEK_PROTOTYPE */ + +/* Define to 1 if you have the `lseek64' function. */ +/* #undef HAVE_LSEEK64 */ + +/* Define to 1 if you have the `lseek64' prototype. */ +#define HAVE_LSEEK64_PROTOTYPE 1 + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#define HAVE_MALLOC 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MALLOC_H 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have a working `mmap' system call. */ +/* #undef HAVE_MMAP */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MNTENT_H */ + +/* Define to 1 if you have the `munmap' function. */ +/* #undef HAVE_MUNMAP */ + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +/* #undef HAVE_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_NET_IF_DL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_NET_IF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PATHS_H 1 + +/* Define to 1 if you have the `random' function. */ +#define HAVE_RANDOM 1 + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#define HAVE_REALLOC 1 + +/* Define to 1 if you have the `select' function. */ +#define HAVE_SELECT 1 + +/* Define to 1 if you have the `srand' function. */ +#define HAVE_SRAND 1 + +/* Define to 1 if you have the `srandom' function. */ +#define HAVE_SRANDOM 1 + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +/* #undef HAVE_STAT_EMPTY_STRING_BUG */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strrchr' function. */ +#define HAVE_STRRCHR 1 + +/* Define to 1 if you have the `strtol' function. */ +#define HAVE_STRTOL 1 + +/* Define to 1 if you have the `strtoul' function. */ +#define HAVE_STRTOUL 1 + +/* Define to 1 if you have the `strtoull' function. */ +#define HAVE_STRTOULL 1 + +/* Define to 1 if `st_blksize' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLKSIZE 1 + +/* Define to 1 if `st_blocks' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 + +/* Define to 1 if `st_rdev' is a member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_RDEV 1 + +/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use + `HAVE_STRUCT_STAT_ST_BLOCKS' instead. */ +#define HAVE_ST_BLOCKS 1 + +/* Define to 1 if you have the `sysconf' function. */ +#define HAVE_SYSCONF 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DISKLABEL_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_DISK_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_FILE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MKDEV_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MMAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MOUNT_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_PRCTL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_QUEUE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SOCKIO_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STATVFS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SYSCALL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UN_H 1 + +/* Define to 1 if you have the `ssize_t' prototype. */ +#define HAVE_TYPE_SSIZE_T 1 + +/* Define to 1 if you have the `uname' function. */ +#define HAVE_UNAME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `utime' function. */ +#define HAVE_UTIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UTIME_H 1 + +/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */ +#define HAVE_UTIME_NULL 1 + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +/* #undef LT_OBJDIR */ + +/* Define to 1 if `major', `minor', and `makedev' are declared in . + */ +/* #undef MAJOR_IN_MKDEV */ + +/* Define to 1 if `major', `minor', and `makedev' are declared in + . */ +/* #undef MAJOR_IN_SYSMACROS */ + +/* Name of package */ +#define PACKAGE "fuse-ext2" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "fuse-ext2" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "fuse-ext2 0.0.7.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "fuse-ext2" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.0.7.1" + +/* Define to the type of arg 1 for `select'. */ +#define SELECT_TYPE_ARG1 int + +/* Define to the type of args 2, 3 and 4 for `select'. */ +#define SELECT_TYPE_ARG234 (fd_set *) + +/* Define to the type of arg 5 for `select'. */ +#define SELECT_TYPE_ARG5 (struct timeval *) + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Version number of package */ +#define VERSION "0.0.7.1" + +/* File Offset size */ +#define _FILE_OFFSET_BITS 64 + +/* Large files support */ +#define _LARGE_FILE_SOURCE /**/ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to rpl_malloc if the replacement function should be used. */ +/* #undef malloc */ + +/* Define to `int' if does not define. */ +/* #undef mode_t */ + +/* Define to `long int' if does not define. */ +/* #undef off_t */ + +/* Define to rpl_realloc if the replacement function should be used. */ +/* #undef realloc */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ + +/* Define to `int' if does not define. */ +/* #undef ssize_t */ + +/* Define to `int' if doesn't define. */ +/* #undef uid_t */ diff --git a/src/lib/fuse-ext2/init.cc b/src/lib/fuse-ext2/init.cc new file mode 100644 index 0000000..731f8ec --- /dev/null +++ b/src/lib/fuse-ext2/init.cc @@ -0,0 +1,104 @@ +/* + * \brief libc_fuse_ext2 + * \author Josef Soentgen + * \date 2013-11-11 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include + +#include +#include + +/* libc includes */ +#include + +extern "C" { + +#include +#include + +extern struct fuse_operations ext2fs_ops; + +struct fuse_chan *fc; +struct fuse *fh; + +static ext2_filsys e2fs; +static struct extfs_data extfs_data; + +char mnt_point[] = "/"; +char options[] = ""; +char device[] = "/dev/blkdev"; +char volname[] = "ext2_volume"; + +} + + +bool Fuse::init_fs(void) +{ + Genode::log("libc_fuse_ext2: try to mount /dev/blkdev..."); + + int err = ext2fs_open("/dev/blkdev", EXT2_FLAG_RW, 0, 0, unix_io_manager, &e2fs); + if (err) { + Genode::error("libc_fuse_ext2: could not mount /dev/blkdev, error: ", err); + return false; + } + + errcode_t rc = ext2fs_read_bitmaps(e2fs); + if (rc) { + Genode::error("libc_fuse_ext2: error while reading bitmaps"); + ext2fs_close(e2fs); + return false; + } + + /* set 1 to enable debug messages */ + extfs_data.debug = 0; + + extfs_data.silent = 0; + extfs_data.force = 0; + extfs_data.readonly = 0; + extfs_data.last_flush = 0; + extfs_data.mnt_point = mnt_point; + extfs_data.options = options; + extfs_data.device = device; + extfs_data.volname = volname; + extfs_data.e2fs = e2fs; + + fh = fuse_new(fc, NULL, &ext2fs_ops, sizeof (ext2fs_ops), &extfs_data); + if (fh == 0) { + Genode::error("libc_fuse_ext2: fuse_new() failed"); + return false; + } + + return true; +} + + +void Fuse::deinit_fs(void) +{ + Genode::log("libc_fuse_ext2: unmount /dev/blkdev..."); + ext2fs_close(e2fs); + + free(fh); +} + + +void Fuse::sync_fs(void) +{ + Genode::log("libc_fuse_ext2: sync file system..."); + ext2fs_flush(e2fs); +} + + +bool Fuse::support_symlinks(void) +{ + return true; +} diff --git a/src/lib/fuse-ext2/patches/bitops.h.patch b/src/lib/fuse-ext2/patches/bitops.h.patch new file mode 100644 index 0000000..cb5f5e7 --- /dev/null +++ b/src/lib/fuse-ext2/patches/bitops.h.patch @@ -0,0 +1,10 @@ ++++ src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit/ext2fs/bitops.h +@@ -98,7 +98,7 @@ + extern int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); + extern int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap bitmap, +- ino_t inode, int num); ++ ext2_ino_t inode, int num); + extern void ext2fs_fast_mark_block_bitmap_range(ext2fs_block_bitmap bitmap, + blk_t block, int num); + extern void ext2fs_fast_unmark_block_bitmap_range(ext2fs_block_bitmap bitmap, diff --git a/src/lib/fuse-ext2/patches/closefs.c.patch b/src/lib/fuse-ext2/patches/closefs.c.patch new file mode 100644 index 0000000..6d142ca --- /dev/null +++ b/src/lib/fuse-ext2/patches/closefs.c.patch @@ -0,0 +1,21 @@ ++++ src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit/ext2fs/closefs.c +@@ -32,19 +32,6 @@ + } + } + +-int ext2fs_bg_has_super(ext2_filsys fs, int group_block) +-{ +- if (!(fs->super->s_feature_ro_compat & +- EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) +- return 1; +- +- if (test_root(group_block, 3) || (test_root(group_block, 5)) || +- test_root(group_block, 7)) +- return 1; +- +- return 0; +-} +- + /* + * ext2fs_super_and_bgd_loc2() + * @fs: ext2 fs pointer diff --git a/src/lib/fuse-ext2/patches/com_err.c.patch b/src/lib/fuse-ext2/patches/com_err.c.patch new file mode 100644 index 0000000..ebfccdb --- /dev/null +++ b/src/lib/fuse-ext2/patches/com_err.c.patch @@ -0,0 +1,10 @@ ++++ src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit/et/com_err.c +@@ -11,6 +11,8 @@ + * express or implied warranty. + */ + ++#include "config.h" ++ + #include + #ifdef HAVE_TERMIOS_H + #include diff --git a/src/lib/fuse-ext2/patches/error_message.c.patch b/src/lib/fuse-ext2/patches/error_message.c.patch new file mode 100644 index 0000000..79b51b3 --- /dev/null +++ b/src/lib/fuse-ext2/patches/error_message.c.patch @@ -0,0 +1,10 @@ ++++ src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit/et/error_message.c +@@ -16,6 +16,8 @@ + * express or implied warranty. + */ + ++#include "config.h" ++ + #include + #include + #include diff --git a/src/lib/fuse-ext2/patches/ext2fs.h.patch b/src/lib/fuse-ext2/patches/ext2fs.h.patch new file mode 100644 index 0000000..56bfd6a --- /dev/null +++ b/src/lib/fuse-ext2/patches/ext2fs.h.patch @@ -0,0 +1,14 @@ ++++ src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit/ext2fs/ext2fs.h +@@ -49,9 +49,12 @@ + #include + #endif + ++typedef unsigned int dev_t; ++ + #include + #include + #include ++#include + + #if EXT2_FLAT_INCLUDES + #include "e2_types.h" diff --git a/src/lib/fuse-ext2/patches/fuse-ext2.c.patch b/src/lib/fuse-ext2/patches/fuse-ext2.c.patch new file mode 100644 index 0000000..c8af5bb --- /dev/null +++ b/src/lib/fuse-ext2/patches/fuse-ext2.c.patch @@ -0,0 +1,23 @@ ++++ src/lib/fuse-ext2/fuse-ext2/fuse-ext2.c +@@ -278,7 +278,7 @@ + goto exit; + } + +-static const struct fuse_operations ext2fs_ops = { ++const struct fuse_operations ext2fs_ops = { + .getattr = op_getattr, + .readlink = op_readlink, + .mknod = op_mknod, +@@ -317,6 +317,7 @@ + .bmap = NULL, + }; + ++#if 0 + int main (int argc, char *argv[]) + { + int err = 0; +@@ -385,3 +386,4 @@ + free(opts.volname); + return err; + } ++#endif diff --git a/src/lib/fuse-ext2/patches/fuse-ext2.h.patch b/src/lib/fuse-ext2/patches/fuse-ext2.h.patch new file mode 100644 index 0000000..05c03b1 --- /dev/null +++ b/src/lib/fuse-ext2/patches/fuse-ext2.h.patch @@ -0,0 +1,19 @@ ++++ src/lib/fuse-ext2/fuse-ext2/fuse-ext2.h +@@ -88,7 +88,7 @@ + static inline ext2_filsys current_ext2fs(void) + { + struct fuse_context *mycontext=fuse_get_context(); +- struct extfs_data *e2data=mycontext->private_data; ++ struct extfs_data *e2data= (struct extfs_data*)mycontext->private_data; + time_t now=time(NULL); + if ((now - e2data->last_flush) > FLUSH_BITMAPS_TIMEOUT) { + ext2fs_write_bitmaps(e2data->e2fs); +@@ -103,7 +103,7 @@ + { + va_list args; + struct fuse_context *mycontext=fuse_get_context(); +- struct extfs_data *e2data=mycontext->private_data; ++ struct extfs_data *e2data=(struct extfs_data*) mycontext->private_data; + if (e2data && (e2data->debug == 0 || e2data->silent == 1)) { + return; + } diff --git a/src/lib/fuse-ext2/patches/gen_bitmap64.c.patch b/src/lib/fuse-ext2/patches/gen_bitmap64.c.patch new file mode 100644 index 0000000..2fb21c6 --- /dev/null +++ b/src/lib/fuse-ext2/patches/gen_bitmap64.c.patch @@ -0,0 +1,7 @@ ++++ src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit/ext2fs/gen_bitmap64.c +@@ -577,4 +577,5 @@ + com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, + "called %s with 64-bit bitmap", func); + #endif ++ return 0; + } diff --git a/src/lib/fuse-ext2/patches/icount.c.patch b/src/lib/fuse-ext2/patches/icount.c.patch new file mode 100644 index 0000000..0d3a7c7 --- /dev/null +++ b/src/lib/fuse-ext2/patches/icount.c.patch @@ -0,0 +1,10 @@ ++++ src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit/ext2fs/icount.c +@@ -9,6 +9,8 @@ + * %End-Header% + */ + ++#include "config.h" ++ + #if HAVE_UNISTD_H + #include + #endif diff --git a/src/lib/fuse-ext2/patches/init_et.c.patch b/src/lib/fuse-ext2/patches/init_et.c.patch new file mode 100644 index 0000000..e5634c6 --- /dev/null +++ b/src/lib/fuse-ext2/patches/init_et.c.patch @@ -0,0 +1,10 @@ ++++ src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit/et/init_et.c +@@ -16,6 +16,8 @@ + * express or implied warranty. + */ + ++#include "config.h" ++ + #include + #include + #ifdef HAVE_STDLIB_H diff --git a/src/lib/fuse-ext2/patches/op_access.c.patch b/src/lib/fuse-ext2/patches/op_access.c.patch new file mode 100644 index 0000000..13a854a --- /dev/null +++ b/src/lib/fuse-ext2/patches/op_access.c.patch @@ -0,0 +1,10 @@ ++++ src/lib/fuse-ext2/fuse-ext2/op_access.c +@@ -18,6 +18,8 @@ + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + ++#include ++ + #include "fuse-ext2.h" + + int op_access (const char *path, int mask) diff --git a/src/lib/fuse-ext2/patches/op_statfs.c.patch b/src/lib/fuse-ext2/patches/op_statfs.c.patch new file mode 100644 index 0000000..bead8ca --- /dev/null +++ b/src/lib/fuse-ext2/patches/op_statfs.c.patch @@ -0,0 +1,14 @@ ++++ src/lib/fuse-ext2/fuse-ext2/op_statfs.c +@@ -41,10 +41,12 @@ + + static int ext2_bg_has_super (ext2_filsys e2fs, int group) + { ++ /* + if (EXT2_HAS_RO_COMPAT_FEATURE(e2fs->super, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER) && + !ext2_group_spare(group)) { + return 0; + } ++ */ + return 1; + } + diff --git a/src/lib/fuse-ext2/patches/res_gdt.c.patch b/src/lib/fuse-ext2/patches/res_gdt.c.patch new file mode 100644 index 0000000..3da1419 --- /dev/null +++ b/src/lib/fuse-ext2/patches/res_gdt.c.patch @@ -0,0 +1,10 @@ ++++ src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit/ext2fs/res_gdt.c +@@ -63,7 +63,7 @@ + errcode_t retval, retval2; + struct ext2_super_block *sb; + struct ext2_inode inode; +- __u32 *dindir_buf, *gdt_buf; ++ __u32 *dindir_buf = 0, *gdt_buf; + unsigned long long apb, inode_size; + /* FIXME-64 - can't deal with extents */ + blk_t dindir_blk, rsv_off, gdt_off, gdt_blk; diff --git a/src/lib/fuse-ext2/patches/rw_bitmaps.c.patch b/src/lib/fuse-ext2/patches/rw_bitmaps.c.patch new file mode 100644 index 0000000..458aeb2 --- /dev/null +++ b/src/lib/fuse-ext2/patches/rw_bitmaps.c.patch @@ -0,0 +1,10 @@ ++++ src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit/ext2fs/rw_bitmaps.c +@@ -34,7 +34,7 @@ + int block_nbytes, inode_nbytes; + unsigned int nbits; + errcode_t retval; +- char *block_buf, *inode_buf; ++ char *block_buf = 0, *inode_buf = 0; + int csum_flag = 0; + blk64_t blk; + blk64_t blk_itr = fs->super->s_first_data_block; diff --git a/src/lib/fuse-ext2/patches/tdb.c.patch b/src/lib/fuse-ext2/patches/tdb.c.patch new file mode 100644 index 0000000..24949a8 --- /dev/null +++ b/src/lib/fuse-ext2/patches/tdb.c.patch @@ -0,0 +1,16 @@ ++++ src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit/ext2fs/tdb.c +@@ -75,12 +75,11 @@ + static char *rep_strdup(const char *s) + { + char *ret; +- int length; ++ size_t length; + if (!s) + return NULL; + +- if (!length) +- length = strlen(s); ++ length = strlen(s); + + ret = malloc(length + 1); + if (ret) { diff --git a/src/lib/fuse-ext2/patches/test_io.c.patch b/src/lib/fuse-ext2/patches/test_io.c.patch new file mode 100644 index 0000000..8e0dbbd --- /dev/null +++ b/src/lib/fuse-ext2/patches/test_io.c.patch @@ -0,0 +1,10 @@ ++++ src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit/ext2fs/test_io.c +@@ -9,6 +9,8 @@ + * %End-Header% + */ + ++#include "config.h" ++ + #include + #include + #if HAVE_UNISTD_H diff --git a/src/lib/fuse-ext2/patches/unix_io.c.patch b/src/lib/fuse-ext2/patches/unix_io.c.patch new file mode 100644 index 0000000..8596db8 --- /dev/null +++ b/src/lib/fuse-ext2/patches/unix_io.c.patch @@ -0,0 +1,10 @@ ++++ src/lib/fuse-ext2/e2fsprogs-1.41.12.newgit/ext2fs/unix_io.c +@@ -200,7 +200,7 @@ + errcode_t retval; + size_t size, alignsize, fragment; + ext2_loff_t location; +- int total = 0, actual; ++ int total = 0, actual = 0; + #define BLOCKALIGN 512 + char sector[BLOCKALIGN]; + diff --git a/src/lib/fuse/fuse.cc b/src/lib/fuse/fuse.cc new file mode 100644 index 0000000..a23ae1f --- /dev/null +++ b/src/lib/fuse/fuse.cc @@ -0,0 +1,299 @@ +/* + * \brief libfuse re-implementation + * \author Josef Soentgen + * \date 2013-11-07 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genodes includes */ +#include +#include + +/* libc includes */ +#include +#include +#include + +#include +#include + +static bool _initialized; +static struct fuse *_fuse; +static struct fuse_context _ctx; + +#if 1 +#define TRACE Genode::log("") +#else +#define TRACE +#endif + +struct fuse* Fuse::fuse() +{ + if (_fuse == 0) { + Genode::error("libfuse: struct fuse is zero"); + abort(); + } + + return _fuse; +} + +bool Fuse::initialized() +{ + return _initialized; +} + +extern "C" { + +void fuse_genode(const char *s) +{ + Genode::log(__func__, ": ", s); +} + +#define FIX_UP_OPERATION1(f, name) \ + if(f->op.name == 0) \ + f->op.name = dummy_op1; + +#define FIX_UP_OPERATION2(f, name) \ + if(f->op.name == 0) \ + f->op.name = dummy_op2; + +static int dummy_op1(void) +{ + TRACE; + return -ENOSYS; +} + +static int dummy_op2(void) +{ + TRACE; + return 0; +} + +static int fill_dir(void *dh, const char *name, const struct stat *sbuf, off_t offset) +{ + static uint32_t fileno = 1; + + struct fuse_dirhandle *dir = (struct fuse_dirhandle*)dh; + + if ((dir->offset + sizeof (struct dirent)) > dir->size) { + Genode::warning("fill_dir buffer full"); + return 1; + } + + struct dirent *entry = (struct dirent *)(((char*)dir->buf) + dir->offset); + Genode::memset(entry, 0, sizeof (struct dirent)); + + if (sbuf) { + entry->d_fileno = sbuf->st_ino; + entry->d_type = IFTODT(sbuf->st_mode); + } + else { + entry->d_fileno = fileno++; + entry->d_type = DT_UNKNOWN; + } + + /* even in a valid sbuf the inode might by 0 */ + if (entry->d_fileno == 0) + entry->d_fileno = fileno++; + + size_t namelen = Genode::strlen(name); + if (namelen > 255) + namelen = 255; + + Genode::strncpy(entry->d_name, name, namelen + 1); + + entry->d_reclen = sizeof (struct dirent); + + dir->offset += sizeof (struct dirent); + + return 0; +} + +/* + * FUSE API + */ + +int fuse_version(void) +{ + return (FUSE_VERSION); +} + +int fuse_main(int argc, char *argv[], + const struct fuse_operations *fsop, void *data) +{ + TRACE; + return -1; +} + +struct fuse* fuse_new(struct fuse_chan *chan, struct fuse_args *args, + const struct fuse_operations *fsop, size_t size, + void *userdata) +{ + TRACE; + + _fuse = reinterpret_cast(malloc(sizeof (struct fuse))); + if (_fuse == 0) { + Genode::error("could not create struct fuse"); + return 0; + } + + _fuse->fc = chan; + _fuse->args = args; + + Genode::memcpy(&_fuse->op, fsop, Genode::min(size, sizeof (_fuse->op))); + + /** + * Defining a dummy function for each fuse operation is cumbersome. + * So let us faithfully ignore the compiler. + */ +#pragma GCC diagnostic ignored "-fpermissive" + + FIX_UP_OPERATION1(_fuse, readlink); + FIX_UP_OPERATION1(_fuse, mknod); + FIX_UP_OPERATION1(_fuse, unlink); + FIX_UP_OPERATION1(_fuse, rmdir); + FIX_UP_OPERATION1(_fuse, symlink); + FIX_UP_OPERATION1(_fuse, rename); + FIX_UP_OPERATION1(_fuse, link); + FIX_UP_OPERATION1(_fuse, chmod); + FIX_UP_OPERATION1(_fuse, chown); + FIX_UP_OPERATION1(_fuse, truncate); + FIX_UP_OPERATION1(_fuse, utime); + FIX_UP_OPERATION2(_fuse, open); + FIX_UP_OPERATION1(_fuse, read); + FIX_UP_OPERATION1(_fuse, write); + FIX_UP_OPERATION1(_fuse, statfs); + FIX_UP_OPERATION1(_fuse, flush); + FIX_UP_OPERATION1(_fuse, release); + FIX_UP_OPERATION1(_fuse, fsync); + FIX_UP_OPERATION1(_fuse, fsyncdir); + FIX_UP_OPERATION1(_fuse, access); + FIX_UP_OPERATION1(_fuse, create); + FIX_UP_OPERATION1(_fuse, utimens); + FIX_UP_OPERATION1(_fuse, read); + FIX_UP_OPERATION1(_fuse, read); + + if (_fuse->op.opendir == 0) + _fuse->op.opendir = _fuse->op.open; + if (_fuse->op.releasedir == 0) + _fuse->op.releasedir = _fuse->op.release; + if (_fuse->op.fgetattr == 0) + _fuse->op.fgetattr = _fuse->op.getattr; + if (_fuse->op.ftruncate == 0) + _fuse->op.ftruncate = _fuse->op.truncate; + + _fuse->filler = fill_dir; + + _fuse->userdata = userdata; + + _ctx.fuse = _fuse; + _ctx.uid = 0; + _ctx.gid = 0; + _ctx.pid = 0; + _ctx.private_data = userdata; + _ctx.umask = 022; + + _initialized = true; + + return _fuse; +} + +int fuse_parse_cmdline(struct fuse_args *args, char **mp, int *mt, int *fg) +{ + TRACE; + return -1; +} + +struct fuse_chan* fuse_mount(const char *dir, struct fuse_args *args) +{ + TRACE; + return 0; +} + +void fuse_remove_signal_handlers(struct fuse_session *se) +{ + TRACE; +} + +int fuse_set_signal_handlers(struct fuse_session *se) +{ + TRACE; + return -1; +} + +struct fuse_session* fuse_get_session(struct fuse *f) +{ + TRACE; + return 0; +} + +struct fuse_context* fuse_get_context(void) +{ + return &_ctx; +} + +int fuse_is_lib_option(const char *opt) +{ + TRACE; + return -1; +} + +int fuse_loop(struct fuse *fuse) +{ + TRACE; + return -1; +} + +int fuse_loop_mt(struct fuse *fuse) +{ + TRACE; + return -1; +} + +int fuse_chan_fd(struct fuse_chan *ch) +{ + TRACE; + return -1; +} + +void fuse_unmount(const char *dir, struct fuse_chan *ch) +{ + TRACE; +} + +int fuse_daemonize(int foreground) +{ + TRACE; + return -1; +} + +void fuse_destroy(struct fuse *f) +{ + TRACE; + + free(f); +} + +void fuse_teardown(struct fuse *f, char *mp) +{ + TRACE; +} + +int fuse_opt_add_arg(struct fuse_args *, const char *) +{ + TRACE; + return -1; +} + +void fuse_opt_free_args(struct fuse_args *) +{ + TRACE; +} + +} /* extern "C" */ diff --git a/src/lib/libc_fuse/plugin.cc b/src/lib/libc_fuse/plugin.cc new file mode 100644 index 0000000..8f2d4b7 --- /dev/null +++ b/src/lib/libc_fuse/plugin.cc @@ -0,0 +1,534 @@ +/* + * \brief Libc libfuse plugin + * \author Josef Soentgen + * \date 2013-11-07 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include + +/* libc plugin includes */ +#include +#include + +/* fuse */ +#include + +/* libc includes */ +#include +#include +#include +#include +#include + +using namespace Genode; + + +/* a little helper to prevent code duplication */ +static inline int check_result(int res) +{ + if (res < 0) { + /** + * FUSE file systems always return -errno as result + * if something went wrong. + */ + errno = -res; + return -1; + } + + return 0; +} + + +/**************************** + ** override libc defaults ** + ****************************/ + +extern "C" int chmod(const char *path, mode_t mode) +{ + return check_result(Fuse::fuse()->op.chmod(path, mode)); +} + + +extern "C" int chown(const char *path, uid_t uid, gid_t gid) +{ + return check_result(Fuse::fuse()->op.chown(path, uid, gid)); +} + + +extern "C" int link(const char *oldpath, const char *newpath) +{ + return check_result(Fuse::fuse()->op.link(oldpath, newpath)); +} + + +/************ + ** Plugin ** + ************/ + +namespace { + + struct Plugin_context : Libc::Plugin_context + { + String<4096> path; + int flags; + int fd_flags; + struct fuse_file_info file_info; + + ::off_t offset; + + Plugin_context(const char *p, int f) + : + path(p), flags(f), offset(0) + { + Genode::memset(&file_info, 0, sizeof (struct fuse_file_info)); + } + + ~Plugin_context() { } + }; + + static inline Plugin_context *context(Libc::File_descriptor *fd) + { + return static_cast(fd->context); + } + + class Plugin : public Libc::Plugin + { + private: + + enum { PLUGIN_PRIORITY = 1 }; + + public: + + /** + * Constructor + */ + Plugin() : Libc::Plugin(PLUGIN_PRIORITY) + { + if (!Fuse::init_fs()) { + error("FUSE fs initialization failed"); + return; + } + } + + ~Plugin() + { + if (Fuse::initialized()) + Fuse::deinit_fs(); + } + + bool supports_mkdir(const char *path, mode_t mode) + { + if (Fuse::initialized() == 0) + return false; + + return true; + } + + bool supports_open(const char *pathname, int flags) + { + if (Genode::strcmp(pathname, "/dev/blkdev") == 0) + return false; + + if (Fuse::initialized() == 0) + return false; + + return true; + } + + bool supports_readlink(const char *path, char *buf, ::size_t bufsiz) + { + if (Fuse::initialized() == 0) + return false; + + return true; + } + + bool supports_rmdir(const char *path) + { + if (Fuse::fuse() == 0) + return false; + return true; + } + + bool supports_stat(const char *path) + { + if (Fuse::initialized() == 0) + return false; + + return true; + } + + bool supports_symlink(const char *oldpath, const char *newpath) + { + if (Fuse::fuse() == 0) + return false; + return true; + } + + bool supports_unlink(const char *path) + { + if (Fuse::fuse() == 0) + return false; + return true; + } + + + int close(Libc::File_descriptor *fd) + { + Plugin_context *ctx = context(fd); + + Fuse::fuse()->op.release(ctx->path.string(), &ctx->file_info); + + destroy(env()->heap(), ctx); + Libc::file_descriptor_allocator()->free(fd); + + return 0; + } + + int fcntl(Libc::File_descriptor *fd, int cmd, long arg) + { + Plugin_context *ctx = context(fd); + + switch (cmd) { + case F_GETFD: + return ctx->fd_flags; + case F_GETFL: + return ctx->flags; + case F_SETFD: + ctx->fd_flags = arg; + return 0; + default: + warning(__func__, ": cmd ", cmd, " not supported"); + return -1; + } + + return -1; /* never reached */ + } + + int fstat(Libc::File_descriptor *fd, struct stat *buf) + { + Plugin_context *ctx = context(fd); + + Genode::memset(buf, 0, sizeof (struct stat)); + + int res = Fuse::fuse()->op.getattr(ctx->path.string(), buf); + if (res != 0) { + errno = -res; + return -1; + } + + return 0; + } + + int fstatfs(Libc::File_descriptor *fd, struct statfs *buf) + { + Plugin_context *ctx = context(fd); + + struct statvfs vfs; + + int res = Fuse::fuse()->op.statfs(ctx->path.string(), &vfs); + if (res != 0) { + errno = -res; + return -1; + } + + Genode::memset(buf, 0, sizeof (struct statfs)); + + buf->f_bsize = vfs.f_bsize; + //buf->f_frsize = vfs.f_frsize; + buf->f_blocks = vfs.f_blocks; + buf->f_bavail = vfs.f_bavail; + buf->f_bfree = vfs.f_bfree; + buf->f_namemax = vfs.f_namemax; + buf->f_files = vfs.f_files; + //buf->f_favail = vfs.f_favail; + buf->f_ffree = vfs.f_ffree; + + return 0; + } + + int ftruncate(Libc::File_descriptor *fd, ::off_t length) + { + Plugin_context *ctx = context(fd); + + int res = Fuse::fuse()->op.ftruncate(ctx->path.string(), length, + &ctx->file_info); + if (res != 0) { + errno = -res; + return -1; + } + + return 0; + } + + ::ssize_t getdirentries(Libc::File_descriptor *fd, char *buf, ::size_t nbytes, + ::off_t *basep) + { + Plugin_context *ctx = context(fd); + + if (nbytes < sizeof (struct dirent)) { + error(__func__, ": buf too small"); + errno = ENOMEM; + return -1; + } + + struct dirent *de = (struct dirent *)buf; + ::memset(de, 0, sizeof (struct dirent)); + + struct fuse_dirhandle dh = { + .filler = Fuse::fuse()->filler, + .buf = buf, + .size = nbytes, + .offset = 0, + }; + + int res = Fuse::fuse()->op.readdir(ctx->path.string(), &dh, + Fuse::fuse()->filler, 0, + &ctx->file_info); + if (res != 0) { + errno = -res; + return -1; + } + + /** + * We have to stat(2) each entry because there are FUSE file + * systems which do not provide a valid struct stat entry in + * its readdir() implementation because only d_ino and d_name + * are specified by POSIX. + */ + ::off_t offset = 0; + while (offset < dh.offset) { + struct dirent *entry = (struct dirent*)(buf + offset); + + /* try to query the type of the file if the type is unknown */ + if (entry->d_type == DT_UNKNOWN) { + Genode::Path<4096> path(entry->d_name, ctx->path.string()); + struct stat sbuf; + res = Fuse::fuse()->op.getattr(path.base(), &sbuf); + if (res == 0) { + entry->d_type = IFTODT(sbuf.st_mode); + entry->d_fileno = sbuf.st_ino ? sbuf.st_ino : 1; + } + } + + offset += sizeof (struct dirent); + } + + /** + * To prevent the libc from being stuck in an endless loop we + * append an empty entry. This is a rather hacky solution but + * for now it suffice. + */ + dh.offset += sizeof (struct dirent); + ((struct dirent*)(buf + dh.offset))->d_reclen = 0; + + return dh.offset; + } + + ::off_t lseek(Libc::File_descriptor *fd, ::off_t offset, int whence) + { + Plugin_context *ctx = context(fd); + + switch (whence) { + case SEEK_SET: + ctx->offset = offset; + return ctx->offset; + + case SEEK_CUR: + ctx->offset += offset; + return ctx->offset; + + case SEEK_END: + if (offset != 0) { + errno = EINVAL; + return -1; + } + ctx->offset = ~0L; + + return (Fuse::fuse()->block_size * Fuse::fuse()->block_count); + + default: + errno = EINVAL; + return -1; + } + } + + int mkdir(const char *pathname, mode_t mode) + { + int res = Fuse::fuse()->op.mkdir(pathname, mode); + + return check_result(res); + } + + Libc::File_descriptor *open(const char *pathname, int flags) + { + /* XXX evaluate flags */ + + Plugin_context *context = new (Genode::env()->heap()) + Plugin_context(pathname, flags); + + int res; + int tries = 0; + do { + /* first try to open pathname */ + res = Fuse::fuse()->op.open(pathname, &context->file_info); + if (res == 0) { + break; + } + + /* try to create pathname if open failed and O_CREAT flag was specified */ + if (flags & O_CREAT && !tries) { + mode_t mode = S_IFREG | 0644; + int res = Fuse::fuse()->op.mknod(pathname, mode, 0); + switch (res) { + case 0: + break; + default: + error(__func__, ": could not create '", pathname, "'"); + destroy(env()->heap(), context); + return 0; + } + + tries++; + continue; + } + + if (res < 0) { + errno = -res; + destroy(env()->heap(), context); + return 0; + } + } + while (true); + + if (flags & O_TRUNC) { + res = Fuse::fuse()->op.ftruncate(pathname, 0, + &context->file_info); + if (res != 0) { + errno = -res; + Fuse::fuse()->op.release(context->path.string(), + &context->file_info); + destroy(env()->heap(), context); + return 0; + } + } + + context->file_info.flags = flags; + + return Libc::file_descriptor_allocator()->alloc(this, context); + } + + ssize_t read(Libc::File_descriptor *fd, void *buf, ::size_t count) + { + Plugin_context *ctx = context(fd); + + int res = Fuse::fuse()->op.read(ctx->path.string(), + reinterpret_cast(buf), + count, ctx->offset, &ctx->file_info); + + if (check_result(res)) + return -1; + + ctx->offset += res; + + return res; + } + + ssize_t readlink(const char *path, char *buf, ::size_t bufsiz) + { + int res = Fuse::fuse()->op.readlink(path, buf, bufsiz); + if (res < 0) { + errno = -res; + return -1; + } + + /** + * We have to trust each FUSE file system to append a + * null byte to buf, which is required according to + * FUSEs documentation. + */ + return Genode::strlen(buf); + } + + int rename(const char *oldpath, const char *newpath) + { + int res = Fuse::fuse()->op.rename(oldpath, newpath); + + return check_result(res); + } + + int rmdir(const char *path) + { + int res = Fuse::fuse()->op.rmdir(path); + + return check_result(res); + } + + int stat(const char *path, struct stat *buf) + { + Genode::memset(buf, 0, sizeof (buf)); + + int res = Fuse::fuse()->op.getattr(path, buf); + + return check_result(res); + } + + int symlink(const char *oldpath, const char *newpath) + { + int res = Fuse::fuse()->op.symlink(oldpath, newpath); + + return check_result(res); + } + + int unlink(const char *path) + { + int res = Fuse::fuse()->op.unlink(path); + + return check_result(res); + } + + ssize_t write(Libc::File_descriptor *fd, const void *buf, ::size_t count) + { + Plugin_context *ctx = context(fd); + + int res = Fuse::fuse()->op.write(ctx->path.string(), + reinterpret_cast(buf), + count, ctx->offset, &ctx->file_info); + + if (check_result(res)) + return -1; + + ctx->offset += res; + + return res; + } + + }; + +} /* unnamed namespace */ + + +void __attribute__((constructor)) init_libc_fuse(void) +{ + /* + * During the initialization of the plugin, we already require the VFS. + * Hence, we need to make sure to initialize the VFS before doing our + * own initialization. + */ + extern void init_libc_vfs(void); + init_libc_vfs(); + + static Plugin plugin; +} diff --git a/src/lib/ntfs-3g/config.h b/src/lib/ntfs-3g/config.h new file mode 100644 index 0000000..0a340bb --- /dev/null +++ b/src/lib/ntfs-3g/config.h @@ -0,0 +1,372 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define this to 1 if you want to enable support of encrypted files in + libntfs and utilities. */ +/* #undef ENABLE_CRYPTO */ + +/* Define to 1 if debug should be enabled */ +/* #undef ENABLE_DEBUG */ + +/* Define to 1 if the nfconv patch should be enabled */ +/* #undef ENABLE_NFCONV */ + +/* Define this to 1 if you want to enable generation of DCE compliant UUIDs. + */ +/* #undef ENABLE_UUID */ + +/* Define to 1 if using internal fuse */ +/* #undef FUSE_INTERNAL */ + +/* Define to 1 if you have the `atexit' function. */ +#define HAVE_ATEXIT 1 + +/* Define to 1 if you have the `basename' function. */ +#define HAVE_BASENAME 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BYTESWAP_H */ + +/* Define to 1 if you have the `clock_gettime' function. */ +/* #undef HAVE_CLOCK_GETTIME */ + +/* Define to 1 if you have the header file. */ +#define HAVE_CTYPE_H 1 + +/* Define to 1 if you have the `daemon' function. */ +/* #undef HAVE_DAEMON */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if you have the `dup2' function. */ +#define HAVE_DUP2 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fdatasync' function. */ +/* #undef HAVE_FDATASYNC */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_FEATURES_H */ + +/* Define to 1 if you have the `ffs' function. */ +#define HAVE_FFS 1 + +/* Define to 1 if you have the `fork' function. */ +#define HAVE_FORK 1 + +/* Define to 1 if you have the `getmntent' function. */ +/* #undef HAVE_GETMNTENT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_GETOPT_H 1 + +/* Define to 1 if you have the `getopt_long' function. */ +#define HAVE_GETOPT_LONG 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `hasmntopt' function. */ +/* #undef HAVE_HASMNTOPT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_LIBGEN_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBINTL_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_FD_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_HDREG_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LINUX_MAJOR_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MACHINE_ENDIAN_H 1 + +/* Define to 1 if mbrtowc and mbstate_t are properly declared. */ +#define HAVE_MBRTOWC 1 + +/* Define to 1 if you have the `mbsinit' function. */ +#define HAVE_MBSINIT 1 + +/* Define to 1 if you have the `memmove' function. */ +#define HAVE_MEMMOVE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MNTENT_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define to 1 if you have the `realpath' function. */ +#define HAVE_REALPATH 1 + + +/* Define to 1 if you have the `regcomp' function. */ +#define HAVE_REGCOMP 1 + +/* Define to 1 if you have the `setlocale' function. */ +#define HAVE_SETLOCALE 1 + +/* Define to 1 if you have the `setxattr' function. */ +/* #undef HAVE_SETXATTR */ + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +#define HAVE_STAT_EMPTY_STRING_BUG 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if stdbool.h conforms to C99. */ +#define HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#define HAVE_STRCASECMP 1 + +/* Define to 1 if you have the `strchr' function. */ +#define HAVE_STRCHR 1 + +/* Define to 1 if you have the `strdup' function. */ +#define HAVE_STRDUP 1 + +/* Define to 1 if you have the `strerror' function. */ +#define HAVE_STRERROR 1 + +/* Define to 1 if you have the `strftime' function. */ +#define HAVE_STRFTIME 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strnlen' function. */ +/* #undef HAVE_STRNLEN */ + +/* Define to 1 if you have the `strsep' function. */ +#define HAVE_STRSEP 1 + +/* Define to 1 if you have the `strtol' function. */ +#define HAVE_STRTOL 1 + +/* Define to 1 if you have the `strtoul' function. */ +#define HAVE_STRTOUL 1 + +/* Define to 1 if `st_atim' is member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_ATIM */ + +/* Define to 1 if `st_atimensec' is member of `struct stat'. */ +/* #undef HAVE_STRUCT_STAT_ST_ATIMENSEC */ + +/* Define to 1 if `st_atimespec' is member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_ATIMESPEC 1 + +/* Define to 1 if `st_blocks' is member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_BLOCKS 1 + +/* Define to 1 if `st_rdev' is member of `struct stat'. */ +#define HAVE_STRUCT_STAT_ST_RDEV 1 + +/* Define to 1 if your `struct stat' has `st_blocks'. Deprecated, use + `HAVE_STRUCT_STAT_ST_BLOCKS' instead. */ +#define HAVE_ST_BLOCKS 1 + +/* Define to 1 if you have the `sysconf' function. */ +#define HAVE_SYSCONF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_BYTEORDER_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_DISK_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_ENDIAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_MKDEV_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MOUNT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STATVFS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_SYSMACROS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_VFS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `utime' function. */ +#define HAVE_UTIME 1 + +/* Define to 1 if you have the `utimensat' function. */ +/* #undef HAVE_UTIMENSAT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UTIME_H 1 + +/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */ +#define HAVE_UTIME_NULL 1 + +/* Define to 1 if you have the `vprintf' function. */ +#define HAVE_VPRINTF 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_WCHAR_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if the system has the type `_Bool'. */ +#define HAVE__BOOL 1 + +/* Don't update /etc/mtab */ +/* #undef IGNORE_MTAB */ + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ + +/* Define to 1 if your C compiler doesn't accept -c and -o together. */ +/* #undef NO_MINUS_C_MINUS_O */ + +/* Don't use default IO ops */ +/* #undef NO_NTFS_DEVICE_DEFAULT_IO_OPS */ + +/* Name of package */ +#define PACKAGE "ntfs3g-genode" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "ntfs-3g" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "ntfs3g-genode 2013.1.3" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "ntfs-3g" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "2013.1.13" + +/* POSIX ACL support */ +/* #undef POSIXACLS */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "2013.1.13" + +/* Define to 1 if this is a Windows OS */ +/* #undef WINDOWS */ + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to 1 if your processor stores words with the least significant byte + first (like Intel and VAX, unlike Motorola and SPARC). */ +#define WORDS_LITTLEENDIAN 1 + +/* system extended attributes mappings */ +/* #undef XATTR_MAPPINGS */ + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Required define if using POSIX threads */ +/* #undef _REENTRANT */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to `long int' if does not define. */ +/* #undef off_t */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/src/lib/ntfs-3g/init.cc b/src/lib/ntfs-3g/init.cc new file mode 100644 index 0000000..0a5bb85 --- /dev/null +++ b/src/lib/ntfs-3g/init.cc @@ -0,0 +1,112 @@ +/* + * \brief libc_fuse_ntfs-3g + * \author Josef Soentgen + * \date 2013-11-11 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include + +#include +#include + +/* libc includes */ +#include + +extern "C" { + +#include +#include +#include + +extern struct fuse_operations ntfs_3g_ops; + +struct fuse_chan *fc; +struct fuse *fh; + +extern ntfs_fuse_context_t **ntfs_fuse_ctx(); +extern int ntfs_open(const char*); +extern void ntfs_close(void); + +} + + +bool Fuse::init_fs(void) +{ + ntfs_set_locale(); + ntfs_log_set_handler(ntfs_log_handler_stderr); + + ntfs_fuse_context_t **ctx = ntfs_fuse_ctx(); + + *ctx = reinterpret_cast(malloc(sizeof (ntfs_fuse_context_t))); + if (!*ctx) { + Genode::error("out of memory"); + return false; + } + + Genode::memset(*ctx, 0, sizeof (ntfs_fuse_context_t)); + (*ctx)->streams = NF_STREAMS_INTERFACE_NONE; + (*ctx)->atime = ATIME_RELATIVE; + (*ctx)->silent = TRUE; + (*ctx)->recover = TRUE; + + /* + *ctx = (ntfs_fuse_context_t) { + .uid = 0, + .gid = 0, + .streams = NF_STREAMS_INTERFACE_NONE, + .atime = ATIME_RELATIVE, + .silent = TRUE, + .recover = TRUE + }; + */ + + Genode::log("libc_fuse_ntfs-3g: try to mount /dev/blkdev..."); + + int err = ntfs_open("/dev/blkdev"); + if (err) { + Genode::error("libc_fuse_ntfs-3g: could not mount /dev/blkdev"); + return false; + } + + fh = fuse_new(fc, NULL, &ntfs_3g_ops, sizeof (ntfs_3g_ops), NULL); + if (fh == 0) { + Genode::error("libc_fuse_exfat: fuse_new() failed"); + ntfs_close(); + return false; + } + + (*ctx)->mounted = TRUE; + + return true; +} + + +void Fuse::deinit_fs(void) +{ + Genode::log("libc_fuse_ntfs-3g: unmount /dev/blkdev..."); + ntfs_close(); + + free(*ntfs_fuse_ctx()); +} + + +void Fuse::sync_fs(void) +{ + Genode::log("libc_fuse_ntfs-3g: sync file system..."); + ntfs_device_sync((*ntfs_fuse_ctx())->vol->dev); +} + + +bool Fuse::support_symlinks(void) +{ + return true; +} diff --git a/src/lib/ntfs-3g/ntfs-3g.c.patch b/src/lib/ntfs-3g/ntfs-3g.c.patch new file mode 100644 index 0000000..b0a6dbe --- /dev/null +++ b/src/lib/ntfs-3g/ntfs-3g.c.patch @@ -0,0 +1,53 @@ ++++ src/lib/ntfs-3g/src/ntfs-3g.c +@@ -151,6 +151,11 @@ + static ntfs_fuse_context_t *ctx; + static u32 ntfs_sequence; + ++ntfs_fuse_context_t **ntfs_fuse_ctx() ++{ ++ return &ctx; ++} ++ + static const char *usage_msg = + "\n" + "%s %s %s %d - Third Generation NTFS Driver\n" +@@ -3266,7 +3271,7 @@ + #endif + #endif /* HAVE_SETXATTR */ + +-static void ntfs_close(void) ++void ntfs_close(void) + { + struct SECURITY_CONTEXT security; + +@@ -3305,7 +3310,7 @@ + ntfs_close(); + } + +-static struct fuse_operations ntfs_3g_ops = { ++struct fuse_operations ntfs_3g_ops = { + #if defined(HAVE_UTIMENSAT) && (defined(FUSE_INTERNAL) || (FUSE_VERSION > 28)) + /* + * Accept UTIME_NOW and UTIME_OMIT in utimens, when +@@ -3387,7 +3392,7 @@ + return 0; + } + +-static int ntfs_open(const char *device) ++int ntfs_open(const char *device) + { + unsigned long flags = 0; + +@@ -3669,6 +3674,7 @@ + ntfs_log_info("Mount options: %s\n", parsed_options); + } + ++#if 0 + int main(int argc, char *argv[]) + { + char *parsed_options = NULL; +@@ -3931,3 +3937,4 @@ + free(opts.device); + return err; + } ++#endif diff --git a/src/server/fuse_fs/README b/src/server/fuse_fs/README new file mode 100644 index 0000000..6128018 --- /dev/null +++ b/src/server/fuse_fs/README @@ -0,0 +1,26 @@ +The fuse_fs server provides access to a FUSE based file system by using a +File_system_session. + +The File_system_session component implementation is independent from each +FUSE based file system. fuse_fs only calls the FUSE operation in question +directly. These operations are provided by the FUSE file system and Genode's +libfuse library makes sure, that each operation is executeable, e.g. by using +a dummy function in case it is not provided by the FUSE file system. +Therefore, to utilize a FUSE file system, the FUSE file system is linked +against libfuse as well as the File_system_session component. For each +fuse_fs server there is a binary (.e.g. 'os/src/server/fuse_fs/ext2'). + +Note: write-support is supported but considered to be experimantal at this +point and for now using it is NOT recommended. + + +To use the ext2_fuse_fs server in noux the following config snippet may be +used: + +! +! +! +! +! +! +! diff --git a/src/server/fuse_fs/directory.h b/src/server/fuse_fs/directory.h new file mode 100644 index 0000000..abf43e5 --- /dev/null +++ b/src/server/fuse_fs/directory.h @@ -0,0 +1,293 @@ +/* + * \brief File-system directory node + * \author Norman Feske + * \author Christian Helmuth + * \author Josef Soentgen + * \date 2013-11-11 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _DIRECTORY_H_ +#define _DIRECTORY_H_ + +/* Genode includes */ +#include +#include + +/* libc includes */ +#include +#include +#include +#include + +/* local includes */ +#include +#include +#include +#include +#include + +#include +#include + + +namespace Fuse_fs { + class Directory; +} + + +class Fuse_fs::Directory : public Node +{ + private: + + typedef Genode::Path Path; + + struct fuse_file_info _file_info; + Path _path; + Allocator &_alloc; + + /** + * Check if the given path points to a directory + */ + bool _is_dir(char const *path) + { + struct stat s; + if (Fuse::fuse()->op.getattr(path, &s) != 0 || ! S_ISDIR(s.st_mode)) + return false; + + return true; + } + + void _open_path(char const *path, bool create) + { + int res; + + if (create) { + + res = Fuse::fuse()->op.mkdir(path, 0755); + + if (res < 0) { + int err = -res; + switch (err) { + case EACCES: + Genode::error("op.mkdir() permission denied"); + throw Permission_denied(); + case EEXIST: + throw Node_already_exists(); + case EIO: + Genode::error("op.mkdir() I/O error occurred"); + throw Lookup_failed(); + case ENOENT: + throw Lookup_failed(); + case ENOTDIR: + throw Lookup_failed(); + case ENOSPC: + Genode::error("op.mkdir() error while expanding directory"); + throw Lookup_failed(); + case EROFS: + throw Permission_denied(); + default: + Genode::error("op.mkdir() returned unexpected error code: ", res); + throw Lookup_failed(); + } + } + } + + res = Fuse::fuse()->op.opendir(path, &_file_info); + + if (res < 0) { + int err = -res; + switch (err) { + case EACCES: + Genode::error("op.opendir() permission denied"); + throw Permission_denied(); + case EIO: + Genode::error("op.opendir() I/O error occurred"); + throw Lookup_failed(); + case ENOENT: + throw Lookup_failed(); + case ENOTDIR: + throw Lookup_failed(); + case ENOSPC: + Genode::error("op.opendir() error while expanding directory"); + throw Lookup_failed(); + case EROFS: + throw Permission_denied(); + default: + Genode::error("op.opendir() returned unexpected error code: ", res); + throw Lookup_failed(); + } + } + } + + size_t _num_entries() + { + char buf[4096]; + + Genode::memset(buf, 0, sizeof (buf)); + + struct fuse_dirhandle dh = { + .filler = Fuse::fuse()->filler, + .buf = buf, + .size = sizeof (buf), + .offset = 0, + }; + + int res = Fuse::fuse()->op.readdir(_path.base(), &dh, + Fuse::fuse()->filler, 0, + &_file_info); + + if (res != 0) + return 0; + + return dh.offset / sizeof (struct dirent); + } + + public: + + Directory(Allocator &alloc, char const *path, bool create) + : + Node(path), + _path(path), + _alloc(alloc) + { + if (!create && !_is_dir(path)) + throw Lookup_failed(); + + _open_path(path, create); + } + + virtual ~Directory() + { + Fuse::fuse()->op.release(_path.base(), &_file_info); + } + + Node *node(char const *path) + { + Path node_path(path, _path.base()); + + struct stat s; + int res = Fuse::fuse()->op.getattr(node_path.base(), &s); + if (res != 0) + throw Lookup_failed(); + + Node *node = 0; + + if (S_ISDIR(s.st_mode)) + node = new (&_alloc) Directory(_alloc, node_path.base(), false); + else if (S_ISREG(s.st_mode)) + node = new (&_alloc) File(this, path, STAT_ONLY); + else if (S_ISLNK(s.st_mode)) + node = new (&_alloc) Symlink(this, path, false); + else + throw Lookup_failed(); + + return node; + } + + struct fuse_file_info *file_info() { return &_file_info; } + + Status status() override + { + struct stat s; + int res = Fuse::fuse()->op.getattr(_path.base(), &s); + if (res != 0) + return Status(); + + Status status; + status.inode = s.st_ino ? s.st_ino : 1; + status.size = _num_entries() * sizeof(Directory_entry); + status.mode = File_system::Status::MODE_DIRECTORY; + + return status; + } + + size_t read(char *dst, size_t len, seek_off_t seek_offset) override + { + if (len < sizeof(Directory_entry)) { + Genode::error("read buffer too small for directory entry"); + return 0; + } + + if (seek_offset % sizeof(Directory_entry)) { + Genode::error("seek offset not aligned to sizeof(Directory_entry)"); + return 0; + } + + seek_off_t index = seek_offset / sizeof(Directory_entry); + + char buf[4096]; + + Genode::memset(buf, 0, sizeof (buf)); + struct dirent *de = (struct dirent *)buf; + + struct fuse_dirhandle dh = { + .filler = Fuse::fuse()->filler, + .buf = buf, + .size = sizeof (buf), + .offset = 0, + }; + + int res = Fuse::fuse()->op.readdir(_path.base(), &dh, + Fuse::fuse()->filler, 0, + &_file_info); + if (res != 0) + return 0; + + if (index > (seek_off_t)(dh.offset / sizeof (struct dirent))) + return 0; + + struct dirent *dent = de + index; + if (!dent) + return 0; + + Directory_entry *e = (Directory_entry *)(dst); + + switch (dent->d_type) { + case DT_REG: e->type = Directory_entry::TYPE_FILE; break; + case DT_DIR: e->type = Directory_entry::TYPE_DIRECTORY; break; + case DT_LNK: e->type = Directory_entry::TYPE_SYMLINK; break; + /** + * There are FUSE file system implementations that do not fill-out + * d_type when calling readdir(). We mark these entries by setting + * their type to DT_UNKNOWN in our libfuse implementation. Afterwards + * we call getattr() on each entry that, hopefully, will yield proper + * results. + */ + case DT_UNKNOWN: + { + Genode::Path<4096> path(dent->d_name, _path.base()); + struct stat sbuf; + res = Fuse::fuse()->op.getattr(path.base(), &sbuf); + if (res == 0) { + switch (IFTODT(sbuf.st_mode)) { + case DT_REG: e->type = Directory_entry::TYPE_FILE; break; + case DT_DIR: e->type = Directory_entry::TYPE_DIRECTORY; break; + } + /* break outer switch */ + break; + } + } + default: + return 0; + } + + strncpy(e->name, dent->d_name, sizeof(e->name)); + + return sizeof(Directory_entry); + } + + size_t write(char const *src, size_t len, seek_off_t seek_offset) override + { + /* writing to directory nodes is not supported */ + return 0; + } +}; + +#endif /* _DIRECTORY_H_ */ diff --git a/src/server/fuse_fs/exfat/target.mk b/src/server/fuse_fs/exfat/target.mk new file mode 100644 index 0000000..5e0bcf7 --- /dev/null +++ b/src/server/fuse_fs/exfat/target.mk @@ -0,0 +1,18 @@ +EXFAT_DIR := $(call select_from_ports,exfat)/src/lib/exfat + +TARGET = exfat_fuse_fs + +SRC_C = $(notdir $(EXFAT_DIR)/fuse/main.c) +SRC_CC = fuse_fs_main.cc \ + init.cc + +LIBS = libc libfuse libexfat +INC_DIR += $(PRG_DIR)/.. + +CC_OPT += -Wno-unused-function + +vpath %.c $(EXFAT_DIR)/fuse +vpath fuse_fs_main.cc $(PRG_DIR)/.. +vpath init.cc $(PRG_DIR)/../../../lib/exfat + +CC_CXX_WARN_STRICT = diff --git a/src/server/fuse_fs/ext2/target.mk b/src/server/fuse_fs/ext2/target.mk new file mode 100644 index 0000000..b32b023 --- /dev/null +++ b/src/server/fuse_fs/ext2/target.mk @@ -0,0 +1,34 @@ +FUSE_EXT2_DIR = $(call select_from_ports,fuse-ext2)/src/lib/fuse-ext2/fuse-ext2 + +TARGET = ext2_fuse_fs + +FILTER_OUT = fuse-ext2.probe.c fuse-ext2.wait.c +SRC_C = $(filter-out $(FILTER_OUT), $(notdir $(wildcard $(FUSE_EXT2_DIR)/*.c))) + + +SRC_CC = fuse_fs_main.cc \ + init.cc + +LIBS = libc libfuse libext2fs + +CC_OPT += -DHAVE_CONFIG_H -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 + +CC_OPT += -Wno-unused-function -Wno-unused-variable \ + -Wno-unused-but-set-variable -Wno-cpp \ + -Wno-maybe-uninitialized + +CC_C_OPT += -std=gnu89 + +CC_C_OPT += -Wno-implicit-function-declaration + + +INC_DIR += $(REP_DIR)/src/lib/fuse-ext2 \ + $(FUSE_EXT2_DIR) + +INC_DIR += $(PRG_DIR)/.. + +vpath %.c $(FUSE_EXT2_DIR) +vpath fuse_fs_main.cc $(PRG_DIR)/.. +vpath init.cc $(PRG_DIR)/../../../lib/fuse-ext2 + +CC_CXX_WARN_STRICT = diff --git a/src/server/fuse_fs/file.h b/src/server/fuse_fs/file.h new file mode 100644 index 0000000..d654c9c --- /dev/null +++ b/src/server/fuse_fs/file.h @@ -0,0 +1,159 @@ +/* + * \brief File node + * \author Norman Feske + * \author Christian Helmuth + * \author Josef Soentgen + * \date 2013-11-26 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _FILE_H_ +#define _FILE_H_ + +/* local includes */ +#include +#include + +#include +#include + +namespace Fuse_fs { + class File; +} + + +class Fuse_fs::File : public Node +{ + private: + + Node *_parent; + + typedef Genode::Path Path; + Path _path; + + struct fuse_file_info _file_info; + + void _open_path(char const *path, Mode mode, bool create, bool trunc) + { + int res; + int tries = 0; + do { + /* first try to open pathname */ + res = Fuse::fuse()->op.open(path, &_file_info); + if (res == 0) { + break; + } + + /* try to create pathname if open failed and create is true */ + if (create && !tries) { + mode_t mode = S_IFREG | 0644; + int res = Fuse::fuse()->op.mknod(path, mode, 0); + switch (res) { + case 0: + break; + default: + Genode::error("could not create '", path, "'"); + throw Lookup_failed(); + } + + tries++; + continue; + } + + if (res < 0) { + throw Lookup_failed(); + } + } + while (true); + + if (trunc) { + res = Fuse::fuse()->op.ftruncate(path, 0, &_file_info); + + if (res != 0) { + Fuse::fuse()->op.release(path, &_file_info); + throw Lookup_failed(); + } + } + } + + size_t _length() + { + struct stat s; + int res = Fuse::fuse()->op.getattr(_path.base(), &s); + if (res != 0) + return 0; + + return s.st_size; + } + + public: + + File(Node *parent, char const *name, Mode mode, + bool create = false, bool trunc = false) + : + Node(name), + _parent(parent), + _path(name, _parent->name()) + { + _open_path(_path.base(), mode, create, trunc); + } + + ~File() + { + Fuse::fuse()->op.release(_path.base(), &_file_info); + } + + struct fuse_file_info *file_info() { return &_file_info; } + + Status status() override + { + struct stat s; + int res = Fuse::fuse()->op.getattr(_path.base(), &s); + if (res != 0) + return Status(); + + Status status; + status.inode = s.st_ino ? s.st_ino : 1; + status.size = s.st_size; + status.mode = File_system::Status::MODE_FILE; + return status; + } + + size_t read(char *dst, size_t len, seek_off_t seek_offset) override + { + /* append mode, use actual length as offset */ + if (seek_offset == ~0ULL) + seek_offset = _length(); + + int ret = Fuse::fuse()->op.read(_path.base(), dst, len, + seek_offset, &_file_info); + return ret < 0 ? 0 : ret; + } + + size_t write(char const *src, size_t len, seek_off_t seek_offset) override + { + /* append mode, use actual length as offset */ + if (seek_offset == ~0ULL) + seek_offset = _length(); + + int ret = Fuse::fuse()->op.write(_path.base(), src, len, + seek_offset, &_file_info); + return ret < 0 ? 0 : ret; + } + + void truncate(file_size_t size) override + { + int res = Fuse::fuse()->op.ftruncate(_path.base(), size, + &_file_info); + if (res == 0) + mark_as_updated(); + } +}; + +#endif /* _FILE_H_ */ diff --git a/src/server/fuse_fs/fuse_fs_main.cc b/src/server/fuse_fs/fuse_fs_main.cc new file mode 100644 index 0000000..bc3889c --- /dev/null +++ b/src/server/fuse_fs/fuse_fs_main.cc @@ -0,0 +1,595 @@ +/* + * \brief FUSE file system + * \author Josef Soentgen + * \date 2013-11-27 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include + +/* libc includes */ +#include + +/* local includes */ +#include +#include +#include + + +namespace Fuse_fs { + + using namespace Genode; + using File_system::Packet_descriptor; + using File_system::Path; + + struct Main; + struct Session_component; + struct Root; +} + + +class Fuse_fs::Session_component : public Session_rpc_object +{ + private: + + typedef File_system::Open_node Open_node; + + Genode::Env &_env; + Allocator &_md_alloc; + Directory &_root; + Id_space _open_node_registry; + bool _writeable; + + Signal_handler _process_packet_handler; + + + /****************************** + ** Packet-stream processing ** + ******************************/ + + /** + * Perform packet operation + * + * \return true on success, false on failure + */ + void _process_packet_op(Packet_descriptor &packet, Open_node &open_node) + { + void * const content = tx_sink()->packet_content(packet); + size_t const length = packet.length(); + + /* resulting length */ + size_t res_length = 0; + bool succeeded = false; + + switch (packet.operation()) { + + case Packet_descriptor::READ: + if (content && (packet.length() <= packet.size())) { + res_length = open_node.node().read((char *)content, length, + packet.position()); + + succeeded = res_length > 0; + } + break; + + case Packet_descriptor::WRITE: + if (content && (packet.length() <= packet.size())) { + res_length = open_node.node().write((char const *)content, length, packet.position()); + + /* File system session can't handle partial writes */ + if (res_length != length) { + Genode::error("partial write detected ", + res_length, " vs ", length); + /* don't acknowledge */ + return; + } + succeeded = true; + } + break; + + case Packet_descriptor::CONTENT_CHANGED: + open_node.register_notify(*tx_sink()); + /* notify_listeners may bounce the packet back*/ + open_node.node().notify_listeners(); + /* otherwise defer acknowledgement of this packet */ + return; + + case Packet_descriptor::READ_READY: + succeeded = true; + /* not supported */ + break; + + case Packet_descriptor::SYNC: + Fuse::sync_fs(); + succeeded = true; + break; + } + + packet.length(res_length); + packet.succeeded(succeeded); + tx_sink()->acknowledge_packet(packet); + } + + void _process_packet() + { + Packet_descriptor packet = tx_sink()->get_packet(); + + /* assume failure by default */ + packet.succeeded(false); + + auto process_packet_fn = [&] (Open_node &open_node) { + _process_packet_op(packet, open_node); + }; + + try { + _open_node_registry.apply(packet.handle(), process_packet_fn); + } catch (Id_space::Unknown_id const &) { + Genode::error("Invalid_handle"); + tx_sink()->acknowledge_packet(packet); + } + } + + /** + * Called by signal handler, executed in the context of the main + * thread (not serialized with the RPC functions) + */ + void _process_packets() + { + while (tx_sink()->packet_avail()) { + + /* + * Make sure that the '_process_packet' function does not + * block. + * + * If the acknowledgement queue is full, we defer packet + * processing until the client processed pending + * acknowledgements and thereby emitted a ready-to-ack + * signal. Otherwise, the call of 'acknowledge_packet()' + * in '_process_packet' would infinitely block the context + * of the main thread. The main thread is however needed + * for receiving any subsequent 'ready-to-ack' signals. + */ + if (!tx_sink()->ready_to_ack()) + return; + + _process_packet(); + } + } + + /** + * Check if string represents a valid path (must start with '/') + */ + static void _assert_valid_path(char const *path) + { + if (!path || path[0] != '/') { + Genode::warning("malformed path '", path, "'"); + throw Lookup_failed(); + } + } + + public: + + /** + * Constructor + */ + Session_component(size_t tx_buf_size, + Genode::Env &env, + char const *root_dir, + bool writeable, + Allocator &md_alloc) + : + Session_rpc_object(env.ram().alloc(tx_buf_size), env.rm(), env.ep().rpc_ep()), + _env(env), + _md_alloc(md_alloc), + _root(*new (&_md_alloc) Directory(_md_alloc, root_dir, false)), + _writeable(writeable), + _process_packet_handler(_env.ep(), *this, &Session_component::_process_packets) + { + _tx.sigh_packet_avail(_process_packet_handler); + _tx.sigh_ready_to_ack(_process_packet_handler); + } + + /** + * Destructor + */ + ~Session_component() + { + Fuse::sync_fs(); + + Dataspace_capability ds = tx_sink()->dataspace(); + _env.ram().free(static_cap_cast(ds)); + destroy(&_md_alloc, &_root); + } + + + /*************************** + ** File_system interface ** + ***************************/ + + File_handle file(Dir_handle dir_handle, Name const &name, Mode mode, bool create) + { + if (!valid_filename(name.string())) + throw Invalid_name(); + + auto file_fn = [&] (Open_node &open_node) { + + Node &dir = open_node.node(); + + if (create && !_writeable) + throw Permission_denied(); + + File *file = new (&_md_alloc) File(&dir, name.string(), mode, create); + + Open_node *open_file = + new (_md_alloc) Open_node(*file, _open_node_registry); + + return open_file->id(); + }; + + try { + return File_handle { + _open_node_registry.apply(dir_handle, file_fn).value + }; + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } + } + + Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create) + { + if (! Fuse::support_symlinks()) { + Genode::error("FUSE file system does not support symlinks"); + throw Permission_denied(); + } + + if (!valid_filename(name.string())) + throw Invalid_name(); + + auto symlink_fn = [&] (Open_node &open_node) { + + Node &dir = open_node.node(); + + if (create && !_writeable) + throw Permission_denied(); + + Symlink *symlink = new (&_md_alloc) Symlink(&dir, name.string(), create); + + Open_node *open_symlink = + new (_md_alloc) Open_node(*symlink, _open_node_registry); + + return Symlink_handle { open_symlink->id().value }; + }; + + try { + return _open_node_registry.apply(dir_handle, symlink_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } + } + + Dir_handle dir(Path const &path, bool create) + { + char const *path_str = path.string(); + + _assert_valid_path(path_str); + + if (create && !_writeable) + throw Permission_denied(); + + if (!path.valid_string()) + throw Name_too_long(); + + Directory *dir_node = new (&_md_alloc) Directory(_md_alloc, path_str, create); + + Open_node *open_dir = + new (_md_alloc) Open_node(*dir_node, _open_node_registry); + + return Dir_handle { open_dir->id().value }; + } + + Node_handle node(Path const &path) + { + char const *path_str = path.string(); + + _assert_valid_path(path_str); + + /** + * FIXME this leads to '/' as parent and 'the rest' as name, + * which fortunatly is in this case not a problem. + */ + Node *node = _root.node(path_str + 1); + + Open_node *open_node = + new (_md_alloc) Open_node(*node, _open_node_registry); + + return open_node->id(); + } + + void close(Node_handle handle) + { + auto close_fn = [&] (Open_node &open_node) { + Node &node = open_node.node(); + destroy(_md_alloc, &open_node); + destroy(_md_alloc, &node); + }; + + try { + _open_node_registry.apply(handle, close_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } + } + + Status status(Node_handle node_handle) + { + auto status_fn = [&] (Open_node &open_node) { + return open_node.node().status(); + }; + + try { + return _open_node_registry.apply(node_handle, status_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } + } + + void control(Node_handle, Control) + { + Genode::error(__func__, " not implemented"); + } + + void unlink(Dir_handle dir_handle, Name const &name) + { + if (!_writeable) + throw Permission_denied(); + + auto unlink_fn = [&] (Open_node &open_node) { + + Node &dir = open_node.node(); + + Absolute_path absolute_path(_root.name()); + + try { + absolute_path.append(dir.name()); + absolute_path.append("/"); + absolute_path.append(name.string()); + } catch (Path_base::Path_too_long) { + throw Invalid_name(); + } + + /* XXX remove direct use of FUSE operations */ + int res = Fuse::fuse()->op.unlink(absolute_path.base()); + + if (res != 0) { + Genode::error("fuse()->op.unlink() returned unexpected error code: ", res); + return; + } + }; + + try { + _open_node_registry.apply(dir_handle, unlink_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } + } + + void truncate(File_handle file_handle, file_size_t size) + { + if (!_writeable) + throw Permission_denied(); + + auto truncate_fn = [&] (Open_node &open_node) { + open_node.node().truncate(size); + }; + + try { + _open_node_registry.apply(file_handle, truncate_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } + } + + void move(Dir_handle from_dir_handle, Name const &from_name, + Dir_handle to_dir_handle, Name const &to_name) + { + if (!_writeable) + throw Permission_denied(); + + auto move_fn = [&] (Open_node &open_from_dir_node) { + + auto inner_move_fn = [&] (Open_node &open_to_dir_node) { + + Node &from_dir = open_from_dir_node.node(); + Node &to_dir = open_to_dir_node.node(); + + Absolute_path absolute_from_path(_root.name()); + Absolute_path absolute_to_path(_root.name()); + + try { + absolute_from_path.append(from_dir.name()); + absolute_from_path.append("/"); + absolute_from_path.append(from_name.string()); + absolute_to_path.append(to_dir.name()); + absolute_to_path.append("/"); + absolute_to_path.append(to_name.string()); + } catch (Path_base::Path_too_long) { + throw Invalid_name(); + } + + /* XXX remove direct use of FUSE operations */ + int res = Fuse::fuse()->op.rename(absolute_to_path.base(), + absolute_from_path.base()); + + if (res != 0) { + Genode::error("fuse()->op.rename() returned unexpected error code: ", res); + return; + } + }; + + try { + _open_node_registry.apply(to_dir_handle, inner_move_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } + }; + + try { + _open_node_registry.apply(from_dir_handle, move_fn); + } catch (Id_space::Unknown_id const &) { + throw Invalid_handle(); + } + } +}; + + +class Fuse_fs::Root : public Root_component +{ + private: + + Genode::Env &_env; + Genode::Attached_rom_dataspace _config { _env, "config" }; + + protected: + + Session_component *_create_session(const char *args) + { + /* + * Determine client-specific policy defined implicitly by + * the client's label. + */ + + char const *root_dir = "."; + bool writeable = false; + + enum { ROOT_MAX_LEN = 256 }; + char root[ROOT_MAX_LEN]; + root[0] = 0; + + Session_label const label = label_from_args(args); + try { + Session_policy policy(label, _config.xml()); + + /* + * Determine directory that is used as root directory of + * the session. + */ + try { + policy.attribute("root").value(root, sizeof(root)); + + /* + * Make sure the root path is specified with a + * leading path delimiter. For performing the + * lookup, we skip the first character. + */ + if (root[0] != '/') + throw Lookup_failed(); + + root_dir = root; + } + catch (Xml_node::Nonexistent_attribute) { + Genode::error("missing \"root\" attribute in policy definition"); + throw Service_denied(); + } + catch (Lookup_failed) { + Genode::error("session root directory \"", + Genode::Cstring(root), "\" does not exist"); + throw Service_denied(); + } + + /* + * Determine if write access is permitted for the session. + */ + writeable = policy.attribute_value("writeable", false); + if (writeable) + Genode::warning("write support in fuse_fs is considered experimental, data-loss may occur."); + + } catch (Session_policy::No_policy_defined) { + Genode::error("Invalid session request, no matching policy"); + throw Genode::Service_denied(); + } + + size_t ram_quota = + Arg_string::find_arg(args, "ram_quota" ).ulong_value(0); + size_t tx_buf_size = + Arg_string::find_arg(args, "tx_buf_size").ulong_value(0); + + if (!tx_buf_size) { + Genode::error(label, " requested a session with a zero length transmission buffer"); + throw Genode::Service_denied(); + } + + /* + * Check if donated ram quota suffices for session data, + * and communication buffer. + */ + size_t session_size = sizeof(Session_component) + tx_buf_size; + if (max((size_t)4096, session_size) > ram_quota) { + Genode::error("insufficient 'ram_quota', got ", ram_quota, " , " + "need ", session_size); + throw Insufficient_ram_quota(); + } + return new (md_alloc()) + Session_component(tx_buf_size, _env, root_dir, writeable, *md_alloc()); + } + + public: + + /** + * Constructor + * + * \param env environment + * \param md_alloc meta-data allocator + */ + Root(Genode::Env & env, Allocator &md_alloc) + : Root_component(env.ep(), md_alloc), + _env(env) { } +}; + + +struct Fuse_fs::Main +{ + Genode::Env & env; + Sliced_heap sliced_heap { env.ram(), env.rm() }; + Root fs_root { env, sliced_heap }; + + Main(Genode::Env & env) : env(env) + { + if (!Fuse::init_fs()) { + Genode::error("FUSE fs initialization failed"); + return; + } + + env.parent().announce(env.ep().manage(fs_root)); + } + + ~Main() + { + if (Fuse::initialized()) { + Fuse::deinit_fs(); + } + } +}; + + +/*************** + ** Component ** + ***************/ + +void Libc::Component::construct(Libc::Env &env) +{ + static Fuse_fs::Main inst(env); +} + diff --git a/src/server/fuse_fs/mode_util.h b/src/server/fuse_fs/mode_util.h new file mode 100644 index 0000000..169a51c --- /dev/null +++ b/src/server/fuse_fs/mode_util.h @@ -0,0 +1,35 @@ +/* + * \brief Mode utilities + * \author Josef Soentgen + * \date 2013-11-26 + */ + +#ifndef _MODE_UTIL_H_ +#define _MODE_UTIL_H_ + +/* Genode includes */ +#include + +/* libc includes */ +#include +#include +#include + +namespace File_system { + int access_mode(File_system::Mode const &mode); +} + + +int File_system::access_mode(File_system::Mode const &mode) +{ + switch (mode) { + case STAT_ONLY: + case READ_ONLY: return O_RDONLY; + case WRITE_ONLY: return O_WRONLY; + case READ_WRITE: return O_RDWR; + } + + return O_RDONLY; +} + +#endif /* _MODE_UTIL_H_ */ diff --git a/src/server/fuse_fs/node.h b/src/server/fuse_fs/node.h new file mode 100644 index 0000000..c4330f7 --- /dev/null +++ b/src/server/fuse_fs/node.h @@ -0,0 +1,62 @@ +/* + * \brief File-system node + * \author Norman Feske + * \author Christian Helmuth + * \author Josef Soentgen + * \date 2013-11-11 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _NODE_H_ +#define _NODE_H_ + +/* Genode includes */ +#include +#include +#include +#include + + +namespace Fuse_fs { + + using namespace Genode; + using namespace File_system; + + typedef Genode::Path Absolute_path; + + class Node; +} + +class Fuse_fs::Node : public Node_base +{ + protected: + + unsigned long _inode; + Absolute_path _name; + + public: + + Node(char const *name) : _name(name) { } + + char const *name() const { return _name.base(); } + + virtual size_t read(char *dst, size_t len, seek_off_t) = 0; + virtual size_t write(char const *src, size_t len, seek_off_t) = 0; + virtual Status status() = 0; + + /* + * File functionality + */ + virtual void truncate(file_size_t size) + { + Genode::error(__PRETTY_FUNCTION__, " called on a non-file node"); + } +}; + +#endif /* _NODE_H_ */ diff --git a/src/server/fuse_fs/ntfs-3g/target.mk b/src/server/fuse_fs/ntfs-3g/target.mk new file mode 100644 index 0000000..09a8de8 --- /dev/null +++ b/src/server/fuse_fs/ntfs-3g/target.mk @@ -0,0 +1,23 @@ +NTFS_3G_DIR := $(call select_from_ports,ntfs-3g)/src/lib/ntfs-3g + +TARGET := ntfs-3g_fuse_fs + +SRC_C := ntfs-3g.c ntfs-3g_common.c +SRC_CC := fuse_fs_main.cc \ + init.cc + +LIBS := libc libfuse libntfs-3g + +CC_OPT := -DHAVE_TIMESPEC -DHAVE_CONFIG_H -DRECORD_LOCKING_NOT_IMPLEMENTED + +INC_DIR += $(PRG_DIR)/.. + +INC_DIR += $(REP_DIR)/src/lib/ntfs-3g \ + $(NTFS_3G_DIR)/src \ + $(REP_DIR)/contrib/$(NTFS_3G)/src + +vpath %.c $(NTFS_3G_DIR)/src +vpath fuse_fs_main.cc $(PRG_DIR)/.. +vpath %.cc $(REP_DIR)/src/lib/ntfs-3g + +CC_CXX_WARN_STRICT = diff --git a/src/server/fuse_fs/open_node.h b/src/server/fuse_fs/open_node.h new file mode 100644 index 0000000..9429768 --- /dev/null +++ b/src/server/fuse_fs/open_node.h @@ -0,0 +1,95 @@ +/* + * \brief Representation of an open file system node within the component (deprecated) + * \author Christian Prochaska + * \date 2017-06-09 + */ + +/* + * Copyright (C) 2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _OPEN_NODE_H_ +#define _OPEN_NODE_H_ + +/* Genode includes */ +#include +#include + +namespace File_system { + /* + * \param NODE component-specific node type + */ + template class Open_node; +} + +template +class File_system::Open_node : public File_system::Node +{ + private: + + Genode::Id_space::Element _element; + + NODE &_node; + Genode::Constructible _listener; + + Listener::Version const _version_when_opened = _node.curr_version(); + + /* + * Flag to track whether the underlying file-system node was + * modified via this 'Open_node'. That is, if closing the 'Open_node' + * should notify listeners of the file. + */ + bool _was_written = false; + + public: + + Open_node(NODE &node, Genode::Id_space &id_space) + : _element(*this, id_space), _node(node) { } + + ~Open_node() + { + if (_listener.constructed()) { + _node.remove_listener(&*_listener); + _listener.destruct(); + } + + /* + * Notify remaining listeners about the changed file + */ + if (_was_written) + _node.notify_listeners(); + } + + NODE &node() { return _node; } + File_system::Listener &listener() { return *_listener; } + + Genode::Id_space::Id id() { return _element.id(); } + + /** + * Register packet stream sink to be notified of node changes + */ + void register_notify(File_system::Sink &sink) + { + /* + * If there was already a handler registered for the node, + * remove the old handler. + */ + if (_listener.constructed()) { + _node.remove_listener(&*_listener); + _listener.destruct(); + } + + /* + * Register new handler + */ + _listener.construct(sink, id(), _version_when_opened); + _node.add_listener(&*_listener); + } + + void mark_as_written() { _was_written = true; } +}; + +#endif /* _OPEN_NODE_H_ */ diff --git a/src/server/fuse_fs/symlink.h b/src/server/fuse_fs/symlink.h new file mode 100644 index 0000000..61a96c4 --- /dev/null +++ b/src/server/fuse_fs/symlink.h @@ -0,0 +1,93 @@ +/* + * \brief Symlink file-system node + * \author Norman Feske + * \author Christian Helmuth + * \author Josef Soentgen + * \date 2013-11-26 + */ + +/* + * Copyright (C) 2013-2017 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SYMLINK_H_ +#define _SYMLINK_H_ + +/* local includes */ +#include + + +namespace Fuse_fs { + class Symlink; +} + + +class Fuse_fs::Symlink : public Node +{ + private: + + Node *_parent; + typedef Genode::Path Path; + Path _path; + + size_t _length() const + { + struct stat s; + int res = Fuse::fuse()->op.getattr(_path.base(), &s); + if (res != 0) + return 0; + + return s.st_size; + } + + public: + + Symlink(Node *parent, char const *name, bool create = false) + : + Node(name), + _parent(parent), + _path(name, parent->name()) + { } + + Status status() override + { + struct stat s; + int res = Fuse::fuse()->op.getattr(_path.base(), &s); + if (res != 0) + return Status(); + + Status status; + status.inode = s.st_ino ? s.st_ino : 1; + status.size = s.st_size; + status.mode = File_system::Status::MODE_FILE; + return status; + } + + size_t read(char *dst, size_t len, seek_off_t seek_offset) override + { + int res = Fuse::fuse()->op.readlink(_path.base(), dst, len); + if (res != 0) + return 0; + + return Genode::strlen(dst); + } + + size_t write(char const *src, size_t len, seek_off_t seek_offset) override + { + /* Ideal symlink operations are atomic. */ + if (seek_offset) return 0; + + int res = Fuse::fuse()->op.symlink(src, _path.base()); + if (res != 0) + return 0; + + return len; + } + + file_size_t length() const { return _length(); } +}; + +#endif /* _SYMLINK_H_ */ diff --git a/src/server/fuse_fs/util.h b/src/server/fuse_fs/util.h new file mode 100644 index 0000000..1e2fddc --- /dev/null +++ b/src/server/fuse_fs/util.h @@ -0,0 +1,103 @@ +/* + * \brief Utilities + * \author Norman Feske + * \author Christian Prochaska + * \date 2012-04-11 + */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +/* Genode includes */ +#include +#include + + +/** + * Return base-name portion of null-terminated path string + */ +static inline char const *basename(char const *path) +{ + char const *start = path; + + for (; *path; path++) + if (*path == '/') + start = path + 1; + + return start; +} + + +/** + * Return true if null-terminated string 'substr' occurs in null-terminated + * string 'str' + */ +static bool string_contains(char const *str, char const *substr) +{ + using namespace Genode; + using Genode::size_t; + + size_t str_len = strlen(str); + size_t substr_len = strlen(substr); + + if (str_len < substr_len) + return false; + + for (size_t i = 0; i <= (str_len - substr_len); i++) + if (strcmp(&str[i], substr, substr_len) == 0) + return true; + + return false; +} + + +/** + * Return true if 'str' is a valid file name + */ +static inline bool valid_filename(char const *str) +{ + if (!str) return false; + + /* must have at least one character */ + if (str[0] == 0) return false; + + /* must not contain '/' or '\' or ':' */ + if (File_system::string_contains(str, '/') || + File_system::string_contains(str, '\\') || + File_system::string_contains(str, ':')) + return false; + + return true; +} + +/** + * Return true if 'str' is a valid path + */ +static inline bool valid_path(char const *str) +{ + if (!str) return false; + + /* must start with '/' */ + if (str[0] != '/') + return false; + + /* must not contain '\' or ':' */ + if (File_system::string_contains(str, '\\') || + File_system::string_contains(str, ':')) + return false; + + /* must not contain "/../" */ + if (string_contains(str, "/../")) return false; + + return true; +} + +/** + * Return true if 'str' is "/" + */ +static inline bool is_root(const char *str) +{ + return (Genode::strcmp(str, "/") == 0); +} + +#endif /* _UTIL_H_ */ diff --git a/src/test/libc_fuse_exfat/target.mk b/src/test/libc_fuse_exfat/target.mk new file mode 100644 index 0000000..83965a3 --- /dev/null +++ b/src/test/libc_fuse_exfat/target.mk @@ -0,0 +1,7 @@ +TARGET = test-libc_fuse_exfat +LIBS = libc libc_fuse_exfat +SRC_CC = main.cc + +vpath %.cc $(REP_DIR)/src/test/libc_vfs + +CC_CXX_WARN_STRICT = diff --git a/src/test/libc_fuse_ext2/target.mk b/src/test/libc_fuse_ext2/target.mk new file mode 100644 index 0000000..de78dd5 --- /dev/null +++ b/src/test/libc_fuse_ext2/target.mk @@ -0,0 +1,7 @@ +TARGET = test-libc_fuse_ext2 +LIBS = libc libc_fuse_ext2 +SRC_CC = main.cc + +vpath %.cc $(REP_DIR)/src/test/libc_vfs + +CC_CXX_WARN_STRICT = diff --git a/src/test/libc_fuse_ntfs-3g/target.mk b/src/test/libc_fuse_ntfs-3g/target.mk new file mode 100644 index 0000000..2d68639 --- /dev/null +++ b/src/test/libc_fuse_ntfs-3g/target.mk @@ -0,0 +1,7 @@ +TARGET = test-libc_fuse_ntfs-3g +LIBS = libc libc_fuse_ntfs-3g +SRC_CC = main.cc + +vpath %.cc $(REP_DIR)/src/test/libc_vfs + +CC_CXX_WARN_STRICT =