mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
libports: add FUSE implementation
This FUSE implementation consists of libfuse, which provides a subset of the FUSE 2.6 API and libc_fuse, which provides support for accessing FUSE based file system via the libc. Fixes #942.
This commit is contained in:
parent
2891653f8a
commit
3a0922001b
161
libports/include/fuse/fuse.h
Normal file
161
libports/include/fuse/fuse.h
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* \brief libfuse re-implementation public API
|
||||
* \author Josef Soentgen
|
||||
* \date 2013-11-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__FUSE_H_
|
||||
#define _INCLUDE__FUSE_H_
|
||||
|
||||
/* libc includes */
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <utime.h>
|
||||
|
||||
|
||||
#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_ */
|
56
libports/include/fuse/fuse_opt.h
Normal file
56
libports/include/fuse/fuse_opt.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* \brief libfuse public API
|
||||
* \author Josef Soentgen
|
||||
* \date 2013-11-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#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_ */
|
127
libports/include/fuse/fuse_private.h
Normal file
127
libports/include/fuse/fuse_private.h
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* \brief libfuse private API
|
||||
* \author Josef Soentgen
|
||||
* \date 2013-11-07
|
||||
* */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#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();
|
||||
|
||||
/* Genode fuse filesystem init functions */
|
||||
void init_fs();
|
||||
void deinit_fs();
|
||||
|
||||
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_ */
|
1
libports/lib/import/import-libfuse.mk
Normal file
1
libports/lib/import/import-libfuse.mk
Normal file
@ -0,0 +1 @@
|
||||
REP_INC_DIR += include/fuse
|
5
libports/lib/mk/libc_fuse.mk
Normal file
5
libports/lib/mk/libc_fuse.mk
Normal file
@ -0,0 +1,5 @@
|
||||
LIBS = libc libfuse
|
||||
|
||||
SRC_CC = plugin.cc
|
||||
|
||||
vpath %.cc $(REP_DIR)/src/lib/libc_fuse
|
9
libports/lib/mk/libfuse.mk
Normal file
9
libports/lib/mk/libfuse.mk
Normal file
@ -0,0 +1,9 @@
|
||||
SRC_CC = fuse.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/include/fuse
|
||||
|
||||
LIBS = libc
|
||||
|
||||
CC_OPT += -fpermissive
|
||||
|
||||
vpath %.cc $(REP_DIR)/src/lib/fuse
|
293
libports/src/lib/fuse/fuse.cc
Normal file
293
libports/src/lib/fuse/fuse.cc
Normal file
@ -0,0 +1,293 @@
|
||||
/*
|
||||
* \brief libfuse re-implementation
|
||||
* \author Josef Soentgen
|
||||
* \date 2013-11-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genodes includes */
|
||||
#include <base/printf.h>
|
||||
#include <util/string.h>
|
||||
|
||||
/* libc includes */
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <fuse.h>
|
||||
#include <fuse_private.h>
|
||||
|
||||
static bool _initialized;
|
||||
static struct fuse *_fuse;
|
||||
static struct fuse_context _ctx;
|
||||
|
||||
#if 1
|
||||
#define TRACE PDBG("")
|
||||
#else
|
||||
#define TRACE
|
||||
#endif
|
||||
|
||||
struct fuse* Fuse::fuse()
|
||||
{
|
||||
if (_fuse == 0) {
|
||||
PERR("libfuse: struct fuse is zero");
|
||||
abort();
|
||||
}
|
||||
|
||||
return _fuse;
|
||||
}
|
||||
|
||||
bool Fuse::initialized()
|
||||
{
|
||||
return _initialized;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void fuse_genode(const char *s)
|
||||
{
|
||||
PLOG("%s: %s", __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) {
|
||||
PWRN("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<struct fuse*>(malloc(sizeof (struct fuse)));
|
||||
if (_fuse == 0) {
|
||||
PERR("could not create struct fuse");
|
||||
return 0;
|
||||
}
|
||||
|
||||
_fuse->fc = chan;
|
||||
_fuse->args = args;
|
||||
|
||||
Genode::memcpy(&_fuse->op, fsop, Genode::min(size, sizeof (_fuse->op)));
|
||||
|
||||
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" */
|
548
libports/src/lib/libc_fuse/plugin.cc
Normal file
548
libports/src/lib/libc_fuse/plugin.cc
Normal file
@ -0,0 +1,548 @@
|
||||
/*
|
||||
* \brief Libc libfuse plugin
|
||||
* \author Josef Soentgen
|
||||
* \date 2013-11-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/allocator_avl.h>
|
||||
#include <base/env.h>
|
||||
#include <base/printf.h>
|
||||
#include <util/string.h>
|
||||
#include <os/path.h>
|
||||
|
||||
/* libc plugin includes */
|
||||
#include <libc-plugin/plugin.h>
|
||||
#include <libc-plugin/fd_alloc.h>
|
||||
|
||||
/* fuse */
|
||||
#include <fuse_private.h>
|
||||
|
||||
/* libc includes */
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
void *operator new (size_t, void *ptr) { return ptr; }
|
||||
|
||||
#define PDBGV(...) if (verbose) PDBG(__VA_ARGS__)
|
||||
static bool const verbose = false;
|
||||
|
||||
/* 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 access(const char *pathname, int mode)
|
||||
{
|
||||
PDBGV("pathname: %s", pathname);
|
||||
return check_result(Fuse::fuse()->op.access(pathname, mode));
|
||||
}
|
||||
*/
|
||||
|
||||
extern "C" int chmod(const char *path, mode_t mode)
|
||||
{
|
||||
PDBGV("path: %s", path);
|
||||
return check_result(Fuse::fuse()->op.chmod(path, mode));
|
||||
}
|
||||
|
||||
|
||||
extern "C" int chown(const char *path, uid_t uid, gid_t gid)
|
||||
{
|
||||
PDBGV("path: %s", path);
|
||||
return check_result(Fuse::fuse()->op.chown(path, uid, gid));
|
||||
}
|
||||
|
||||
|
||||
extern "C" int link(const char *oldpath, const char *newpath)
|
||||
{
|
||||
PDBGV("oldpath: %s", oldpath);
|
||||
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<Plugin_context *>(fd->context);
|
||||
}
|
||||
|
||||
class Plugin : public Libc::Plugin
|
||||
{
|
||||
private:
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Plugin()
|
||||
{
|
||||
Fuse::init_fs();
|
||||
}
|
||||
|
||||
~Plugin()
|
||||
{
|
||||
Fuse::deinit_fs();
|
||||
}
|
||||
|
||||
bool supports_mkdir(const char *path, mode_t mode)
|
||||
{
|
||||
PDBGV("path: %s", path);
|
||||
if (Fuse::initialized() == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool supports_open(const char *pathname, int flags)
|
||||
{
|
||||
PDBGV("pathname: %s", pathname);
|
||||
|
||||
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)
|
||||
{
|
||||
PDBGV("path: %s", path);
|
||||
if (Fuse::initialized() == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool supports_stat(const char *path)
|
||||
{
|
||||
PDBGV("path: %s", path);
|
||||
if (Fuse::initialized() == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool supports_symlink(const char *oldpath, const char *newpath)
|
||||
{
|
||||
PDBGV("path: %s", oldpath);
|
||||
if (Fuse::fuse() == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool supports_unlink(const char *path)
|
||||
{
|
||||
PDBGV("path: %s", path);
|
||||
if (Fuse::fuse() == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int close(Libc::File_descriptor *fd)
|
||||
{
|
||||
Plugin_context *ctx = context(fd);
|
||||
|
||||
PDBGV("path: %s", ctx->path.string());
|
||||
|
||||
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:
|
||||
PDBG("cmd %d not supported", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1; /* never reached */
|
||||
}
|
||||
|
||||
int fstat(Libc::File_descriptor *fd, struct stat *buf)
|
||||
{
|
||||
Plugin_context *ctx = context(fd);
|
||||
|
||||
PDBGV("path: %s", ctx->path.string());
|
||||
|
||||
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);
|
||||
|
||||
PDBGV("path: %s", ctx->path.string());
|
||||
|
||||
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);
|
||||
|
||||
PDBGV("path: %s", ctx->path.string());
|
||||
|
||||
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);
|
||||
PDBGV("path: %s", ctx->path.string());
|
||||
|
||||
if (nbytes < sizeof (struct dirent)) {
|
||||
PERR("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);
|
||||
PDBGV("path: %s", ctx->path.string());
|
||||
|
||||
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)
|
||||
{
|
||||
PDBGV("pathname: %s", pathname);
|
||||
int res = Fuse::fuse()->op.mkdir(pathname, mode);
|
||||
|
||||
return check_result(res);
|
||||
}
|
||||
|
||||
Libc::File_descriptor *open(const char *pathname, int flags)
|
||||
{
|
||||
/* XXX evaluate flags */
|
||||
PDBGV("pathname: %s", pathname);
|
||||
|
||||
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:
|
||||
PERR("could not create '%s'", 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);
|
||||
PDBGV("path: %s", ctx->path.string());
|
||||
|
||||
int res = Fuse::fuse()->op.read(ctx->path.string(),
|
||||
reinterpret_cast<char*>(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)
|
||||
{
|
||||
PDBGV("path: %s", path);
|
||||
|
||||
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)
|
||||
{
|
||||
PDBGV("oldpath: %s newpath: %s", oldpath, newpath);
|
||||
int res = Fuse::fuse()->op.rename(oldpath, newpath);
|
||||
|
||||
return check_result(res);
|
||||
}
|
||||
|
||||
int stat(const char *path, struct stat *buf)
|
||||
{
|
||||
PDBGV("path: %s", path);
|
||||
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)
|
||||
{
|
||||
PDBGV("oldpath: %s newpath: %s", oldpath, newpath);
|
||||
int res = Fuse::fuse()->op.symlink(oldpath, newpath);
|
||||
|
||||
return check_result(res);
|
||||
}
|
||||
|
||||
int unlink(const char *path)
|
||||
{
|
||||
PDBGV("path: %s", 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);
|
||||
|
||||
PDBGV("path: %s", ctx->path.string());
|
||||
int res = Fuse::fuse()->op.write(ctx->path.string(),
|
||||
reinterpret_cast<const char*>(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)
|
||||
{
|
||||
PDBGV("using the libc_fuse plugin");
|
||||
static Plugin plugin;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user