--- 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}
--- 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 <stdlib.h>
#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) {
--- 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 <event2/event.h>
#include <fuse/fuse_opt.h>
-#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,
};
--- 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 <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-
-#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);
-}
-
--- 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
-
--- /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 <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+#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);
+}
+
--- /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
+
--- /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 */
+
--- /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 <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#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;
+}
--- /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 <fuse/fuse_lowlevel.h>
+
+/*
+ * 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 */
--- /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 <event2/event.h>
+
+#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);
+}
+