# HG changeset patch # User Tero Marttila # Date 1222449082 -10800 # Node ID d2036d7799fdc6f3b13bb55811444fb7683fe0dc # Parent dc86636257c2803267e5863bfce16b6b29bc8b01 new 'simple' module, plus hello_simple diff -r dc86636257c2 -r d2036d7799fd Makefile --- a/Makefile Fri Sep 26 15:35:58 2008 +0300 +++ b/Makefile Fri Sep 26 20:11:22 2008 +0300 @@ -12,7 +12,8 @@ BIN_NAMES = hello helloworld bin/helloworld: -bin/hello: obj/evfuse.o obj/lib/common.o obj/lib/signals.o +bin/hello: obj/evfuse.o obj/lib/log.o obj/lib/signals.o +bin/simple_hello: obj/evfuse.o obj/lib/log.o obj/lib/signals.o obj/simple.o # computed LDFLAGS = ${LIBRARY_PATHS} ${LIBRARY_LIST} diff -r dc86636257c2 -r d2036d7799fd src/evfuse.c --- a/src/evfuse.c Fri Sep 26 15:35:58 2008 +0300 +++ b/src/evfuse.c Fri Sep 26 20:11:22 2008 +0300 @@ -4,7 +4,7 @@ #include #include "evfuse.h" -#include "lib/common.h" +#include "lib/log.h" struct evfuse { // our mountpoint @@ -58,8 +58,8 @@ return; error: - // XXX: fail - FATAL("no error handling yet..."); + // fail + evfuse_close(ctx); } struct evfuse *evfuse_new (struct event_base *evbase, struct fuse_args *args, struct fuse_lowlevel_ops *llops, void *cb_data) { diff -r dc86636257c2 -r d2036d7799fd src/hello.c --- a/src/hello.c Fri Sep 26 15:35:58 2008 +0300 +++ b/src/hello.c Fri Sep 26 20:11:22 2008 +0300 @@ -5,7 +5,7 @@ #include #include -#include "lib/common.h" +#include "lib/log.h" #include "lib/math.h" #include "lib/signals.h" #include "evfuse.h" @@ -87,8 +87,6 @@ size_t off; }; -#define DIRBUF_INITIAL_SIZE 1024 - static int dirbuf_init (struct dirbuf *buf, size_t req_size) { buf->len = req_size; buf->off = 0; @@ -250,6 +248,12 @@ EWARNING(err, "failed to send error reply"); } +void hello_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) { + INFO("[hello.getxattr] ino=%lu, name=`%s', size=%zu", ino, name, size); + + fuse_reply_err(req, ENOSYS); +} + struct fuse_lowlevel_ops hello_llops = { .init = &hello_init, .destroy = &hello_destroy, @@ -262,6 +266,8 @@ .read = &hello_read, .readdir = &hello_readdir, + + .getxattr = hello_getxattr, }; diff -r dc86636257c2 -r d2036d7799fd src/lib/common.c --- a/src/lib/common.c Fri Sep 26 15:35:58 2008 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -#include -#include -#include -#include -#include - -#include "common.h" - -static void _generic_err_vargs (int use_stderr, const char *func, int perr, const char *fmt, va_list va) { - FILE *stream = use_stderr ? stderr : stdout; - - if (func) - fprintf(stream, "%s: ", func); - - vfprintf(stream, fmt, va); - - if (perr) - fprintf(stream, ": %s\n", strerror(perr > 0 ? errno : -perr)); - - fprintf(stream, "\n"); -} - -void _generic_err (int use_stderr, const char *func, int perr, const char *fmt, ...) { - va_list va; - - va_start(va, fmt); - _generic_err_vargs(use_stderr, func, perr, fmt, va); - va_end(va); -} - -void _generic_err_exit (int use_stderr, const char *func, int perr, const char *fmt, ...) { - va_list va; - - va_start(va, fmt); - _generic_err_vargs(use_stderr, func, perr, fmt, va); - va_end(va); - - exit(EXIT_FAILURE); -} - diff -r dc86636257c2 -r d2036d7799fd src/lib/common.h --- a/src/lib/common.h Fri Sep 26 15:35:58 2008 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ - -/* - * error handling - */ - -void _generic_err ( /*int level, */ int use_stderr, const char *func, int perr, const char *fmt, ...) - __attribute__ ((format (printf, 4, 5))); - -// needs to be defined as its own function for the noreturn attribute -void _generic_err_exit ( /* int level, */ int used_stderr, const char *func, int perr, const char *fmt, ...) - __attribute__ ((format (printf, 4, 5))) - __attribute__ ((noreturn)); - -enum _debug_level { - DEBUG_FATAL, - DEBUG_ERROR, - DEBUG_WARNING, - DEBUG_INFO, - DEBUG_DEBUG, -}; - -// not currently used -extern enum _debug_level _cur_debug_level; - -// various kinds of ways to handle an error, 2**3 of them, *g* -#define info(...) _generic_err( 0, NULL, 0, __VA_ARGS__ ) -#define error(...) _generic_err( 1, NULL, 0, __VA_ARGS__ ) -#define err_exit(...) _generic_err_exit( 1, NULL, 0, __VA_ARGS__ ) -#define perr(...) _generic_err( 1, NULL, 1, __VA_ARGS__ ) -#define perr_exit(...) _generic_err_exit( 1, NULL, 1, __VA_ARGS__ ) -#define err_func(func, ...) _generic_err( 1, func, 0, __VA_ARGS__ ) -#define err_func_exit(func, ...) _generic_err_exit( 1, func, 0, __VA_ARGS__ ) -#define perr_func(func, ...) _generic_err( 1, func, 1, __VA_ARGS__ ) -#define perr_func_exit(func, ...) _generic_err_exit( 1, func, 1, __VA_ARGS__ ) -#define eerr_func(func, err, ...) _generic_err( 1, func, err,__VA_ARGS__ ) - -/* - * error(func + colon + msg, ...) + goto error - * err = negative error code - */ -#define ERROR(...) do { err_func(__func__, __VA_ARGS__); goto error; } while (0) -#define PERROR(...) do { perr_func(__func__, __VA_ARGS__); goto error; } while (0) -#define EERROR(err, ...) do { eerr_func(__func__, (err), __VA_ARGS__); goto error; } while (0) -#define FATAL(...) err_func_exit(__func__, __VA_ARGS__) -#define PFATAL(...) perr_func_exit(__func__, __VA_ARGS__) -#define WARNING(...) err_func(__func__, __VA_ARGS__) -#define PWARNING(...) perr_func(__func__, __VA_ARGS__) -#define EWARNING(err, ...) eerr_func(__func__, (err), __VA_ARGS__) - -#ifdef DEBUG_ENABLED -#define DEBUG(...) err_func(__func__, __VA_ARGS__) -#else -#define DEBUG(...) (void) (0) -#endif - -// default is to enable INFO -#ifdef INFO_DISABLED - #define INFO_ENABLED 0 -#else - #ifndef INFO_ENABLED - #define INFO_ENABLED 1 - #endif -#endif - -#if INFO_ENABLED -#define INFO(...) info(__VA_ARGS__) -#else -#define INFO(...) (void) (0) -#endif - diff -r dc86636257c2 -r d2036d7799fd src/lib/log.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/log.c Fri Sep 26 20:11:22 2008 +0300 @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include + +#include "log.h" + +static void _generic_err_vargs (int use_stderr, const char *func, int perr, const char *fmt, va_list va) { + FILE *stream = use_stderr ? stderr : stdout; + + if (func) + fprintf(stream, "%s: ", func); + + vfprintf(stream, fmt, va); + + if (perr) + fprintf(stream, ": %s\n", strerror(perr > 0 ? errno : -perr)); + + fprintf(stream, "\n"); +} + +void _generic_err (int use_stderr, const char *func, int perr, const char *fmt, ...) { + va_list va; + + va_start(va, fmt); + _generic_err_vargs(use_stderr, func, perr, fmt, va); + va_end(va); +} + +void _generic_err_exit (int use_stderr, const char *func, int perr, const char *fmt, ...) { + va_list va; + + va_start(va, fmt); + _generic_err_vargs(use_stderr, func, perr, fmt, va); + va_end(va); + + exit(EXIT_FAILURE); +} + diff -r dc86636257c2 -r d2036d7799fd src/lib/log.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/log.h Fri Sep 26 20:11:22 2008 +0300 @@ -0,0 +1,70 @@ + +/* + * error handling + */ + +void _generic_err ( /*int level, */ int use_stderr, const char *func, int perr, const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))); + +// needs to be defined as its own function for the noreturn attribute +void _generic_err_exit ( /* int level, */ int used_stderr, const char *func, int perr, const char *fmt, ...) + __attribute__ ((format (printf, 4, 5))) + __attribute__ ((noreturn)); + +enum _debug_level { + DEBUG_FATAL, + DEBUG_ERROR, + DEBUG_WARNING, + DEBUG_INFO, + DEBUG_DEBUG, +}; + +// not currently used +extern enum _debug_level _cur_debug_level; + +// various kinds of ways to handle an error, 2**3 of them, *g* +#define info(...) _generic_err( 0, NULL, 0, __VA_ARGS__ ) +#define error(...) _generic_err( 1, NULL, 0, __VA_ARGS__ ) +#define err_exit(...) _generic_err_exit( 1, NULL, 0, __VA_ARGS__ ) +#define perr(...) _generic_err( 1, NULL, 1, __VA_ARGS__ ) +#define perr_exit(...) _generic_err_exit( 1, NULL, 1, __VA_ARGS__ ) +#define err_func(func, ...) _generic_err( 1, func, 0, __VA_ARGS__ ) +#define err_func_exit(func, ...) _generic_err_exit( 1, func, 0, __VA_ARGS__ ) +#define perr_func(func, ...) _generic_err( 1, func, 1, __VA_ARGS__ ) +#define perr_func_exit(func, ...) _generic_err_exit( 1, func, 1, __VA_ARGS__ ) +#define eerr_func(func, err, ...) _generic_err( 1, func, err,__VA_ARGS__ ) + +/* + * error(func + colon + msg, ...) + goto error + * err = negative error code + */ +#define ERROR(...) do { err_func(__func__, __VA_ARGS__); goto error; } while (0) +#define PERROR(...) do { perr_func(__func__, __VA_ARGS__); goto error; } while (0) +#define EERROR(err, ...) do { eerr_func(__func__, (err), __VA_ARGS__); goto error; } while (0) +#define FATAL(...) err_func_exit(__func__, __VA_ARGS__) +#define PFATAL(...) perr_func_exit(__func__, __VA_ARGS__) +#define WARNING(...) err_func(__func__, __VA_ARGS__) +#define PWARNING(...) perr_func(__func__, __VA_ARGS__) +#define EWARNING(err, ...) eerr_func(__func__, (err), __VA_ARGS__) + +#ifdef DEBUG_ENABLED +#define DEBUG(...) err_func(__func__, __VA_ARGS__) +#else +#define DEBUG(...) (void) (0) +#endif + +// default is to enable INFO +#ifdef INFO_DISABLED + #define INFO_ENABLED 0 +#else + #ifndef INFO_ENABLED + #define INFO_ENABLED 1 + #endif +#endif + +#if INFO_ENABLED +#define INFO(...) info(__VA_ARGS__) +#else +#define INFO(...) (void) (0) +#endif + diff -r dc86636257c2 -r d2036d7799fd src/lib/misc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/misc.h Fri Sep 26 20:11:22 2008 +0300 @@ -0,0 +1,10 @@ +#ifndef LIB_UTIL_H +#define LIB_UTIL_H + +/* + * Initialize the given *value* with zeros + */ +#define ZINIT(obj) memset(&(obj), 0, sizeof((obj))) + +#endif /* LIB_UTIL_H */ + diff -r dc86636257c2 -r d2036d7799fd src/simple.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/simple.c Fri Sep 26 20:11:22 2008 +0300 @@ -0,0 +1,145 @@ +#include +#include +#include +#include + +#include "simple.h" +#include "lib/log.h" +#include "lib/misc.h" + +struct simple_fs { + const struct simple_node *inode_table; + + size_t inode_count; +}; + +/* + * Used for stat/entry timeouts... not sure how this should really be set. + */ +#define CACHE_TIMEOUT 1.0 + +static void _simple_stat (struct stat *stat, const struct simple_node *node) { + stat->st_ino = node->inode; + stat->st_mode = node->mode_type | node->mode_perm; + stat->st_nlink = 1; + stat->st_size = node->data ? strlen(node->data) : 0; +} + +static int _simple_check_ino (struct simple_fs *fs, fuse_ino_t ino) { + return (ino < 1 || ino > fs->inode_count) ? EIO : 0; +} + +static void simple_lookup (fuse_req_t req, fuse_ino_t parent, const char *name) { + struct simple_fs *fs = fuse_req_userdata(req); + const struct simple_node *node; + struct fuse_entry_param e; ZINIT(e); + int err; + + INFO("[simple.lookup %p] parent=%lu, name=`%s'", fs, parent, name); + + // find the matching node + for (node = fs->inode_table; node->inode > 0; node++) { + if (node->parent == parent && strcmp(node->name, name) == 0) + break; + + } + + // did we find it? + if (node->inode) { + // set up the entry + e.ino = node->inode; + e.generation = 0x01; + _simple_stat(&e.attr, node); + e.attr_timeout = CACHE_TIMEOUT; + e.entry_timeout = CACHE_TIMEOUT; + + // reply + if ((err = fuse_reply_entry(req, &e))) + EERROR(err, "fuse_reply_entry"); + + } else { + // not found + err = ENOENT; + goto error; + } + + // success + return; + +error: + if ((err = fuse_reply_err(req, err))) + EWARNING(err, "fuse_reply_err"); +} + +static void simple_getattr (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) { + struct simple_fs *fs = fuse_req_userdata(req); + const struct simple_node *node; + struct stat stbuf; ZINIT(stbuf); + int err; + + INFO("[simple.getattr %p] ino=%lu", fs, ino); + + // make sure ino is valid + if ((err = _simple_check_ino(fs, ino))) + ERROR("invalid inode"); + + // look up the node + node = fs->inode_table + (ino - 1); + + // set up the stbuf + _simple_stat(&stbuf, node); + + // reply + if ((err = fuse_reply_attr(req, &stbuf, CACHE_TIMEOUT))) + EERROR(err, "fuse_reply_attr"); + + // suceccss + return; + +error: + if ((err = fuse_reply_err(req, err))) + EWARNING(err, "fuse_reply_err"); +} + + +/* + * Define our fuse_lowlevel_ops struct. + */ +static struct fuse_lowlevel_ops simple_ops = { + .lookup = simple_lookup, + + .getattr = simple_getattr, +}; + +struct fuse_lowlevel_ops *simple_init () { + return &simple_ops; +} + +struct simple_fs *simple_new (const struct simple_node *node_list) { + struct simple_fs *fs = NULL; + const struct simple_node *node; + + // generate + if ((fs = calloc(1, sizeof(*fs))) == NULL) + ERROR("calloc"); + + // remember node_list + fs->inode_count = 0; + fs->inode_table = node_list; + + // validate it + for (node = fs->inode_table; node->inode; node++) { + // update inode_count + fs->inode_count++; + + // check that parent is valid + assert(node->inode == fs->inode_count); + assert(node->parent < node->inode); + } + + // success + return fs; + +error: + return NULL; +} diff -r dc86636257c2 -r d2036d7799fd src/simple.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/simple.h Fri Sep 26 20:11:22 2008 +0300 @@ -0,0 +1,46 @@ +#ifndef SIMPLE_H +#define SIMPLE_H + +/* + * A simple static in-memory filesystem structure. + */ + +#include + +/* + * A simple file/dir. + */ +struct simple_node { + // inode number + fuse_ino_t inode; + + // mode + mode_t mode_type; + mode_t mode_perm; + + // parent node + fuse_ino_t parent; + + // name + const char *name; + + // data + const char *data; +}; + +/* + * General information. + */ +struct simple_fs; + +/* + * Initialize simple, and get the fuse_lowlevel_ops. + */ +struct fuse_lowlevel_ops *simple_init (); + +/* + * Create a new simple_fs. + */ +struct simple_fs *simple_new (const struct simple_node *node_list); + +#endif /* SIMPLE_H */ diff -r dc86636257c2 -r d2036d7799fd src/simple_hello.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/simple_hello.c Fri Sep 26 20:11:22 2008 +0300 @@ -0,0 +1,71 @@ + +#include + +#include "lib/log.h" +#include "lib/signals.h" +#include "evfuse.h" +#include "simple.h" + +static struct hello { + struct event_base *ev_base; + + struct signals *signals; + + struct simple_fs *fs; + + struct evfuse *ev_fuse; + +} ctx; + +static struct simple_node node_list[] = { + { 1, S_IFDIR, 0555, 0, NULL, NULL }, + { 2, S_IFREG, 0444, 1, "hello", "Hello World!\n" }, + { 0, 0, 0, 0, NULL, NULL }, +}; + +int main (int argc, char **argv) { + struct fuse_args fuse_args = FUSE_ARGS_INIT(argc, argv); + + // init libevent + if ((ctx.ev_base = event_base_new()) == NULL) + ERROR("event_base_new"); + + // setup signals + if ((ctx.signals = signals_default(ctx.ev_base)) == NULL) + ERROR("signals_default"); + + // setup fs + if ((ctx.fs = simple_new(node_list)) == NULL) + ERROR("simple_new"); + + // open fuse + if ((ctx.ev_fuse = evfuse_new(ctx.ev_base, &fuse_args, simple_init(), ctx.fs)) == NULL) + ERROR("evfuse_new"); + + // run libevent + INFO("running libevent loop"); + + if (event_base_dispatch(ctx.ev_base)) + PERROR("event_base_dispatch"); + + // clean shutdown + +error : + // cleanup + if (ctx.ev_fuse) + evfuse_close(ctx.ev_fuse); + +/* + if (ctx.fs) + simple_close(ctx.fs); +*/ + + if (ctx.signals) + signals_free(ctx.signals); + + if (ctx.ev_base) + event_base_free(ctx.ev_base); + + fuse_opt_free_args(&fuse_args); +} +