--- a/src/simple.c Fri Sep 26 20:39:51 2008 +0300
+++ b/src/simple.c Fri Sep 26 21:13:35 2008 +0300
@@ -4,6 +4,7 @@
#include <assert.h>
#include "simple.h"
+#include "dirbuf.h"
#include "lib/log.h"
#include "lib/misc.h"
@@ -25,8 +26,20 @@
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;
+/*
+ * Fetch the simple_node for the given inode.
+ *
+ * Returns NULL for invalid inodes.
+ */
+static const struct simple_node *_simple_get_ino (struct simple_fs *fs, fuse_ino_t ino) {
+ // make sure it's a valid inode
+ if (ino < 1 || ino > fs->inode_count) {
+ WARNING("invalid inode=%zu", ino);
+ return NULL;
+ }
+
+ // return the node
+ return fs->inode_table + (ino - 1);
}
static void simple_lookup (fuse_req_t req, fuse_ino_t parent, const char *name) {
@@ -79,13 +92,10 @@
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);
-
+ // look up the node
+ if ((node = _simple_get_ino(fs, ino)) == NULL)
+ EERROR(err = EINVAL, "bad inode");
+
// set up the stbuf
_simple_stat(&stbuf, node);
@@ -101,6 +111,60 @@
EWARNING(err, "fuse_reply_err");
}
+void simple_readdir (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off, struct fuse_file_info *fi) {
+ struct simple_fs *fs = fuse_req_userdata(req);
+ const struct simple_node *dir_node, *node;
+ struct dirbuf buf;
+ int err;
+
+ INFO("[simple.readdir] ino=%lu, size=%zu, off=%zu, fi=%p", ino, size, off, fi);
+
+ // look up the inode
+ if ((dir_node = _simple_get_ino(fs, ino)) == NULL)
+ EERROR(err = EINVAL, "bad inode");
+
+ // check that it's a dir
+ if (dir_node->mode_type != S_IFDIR)
+ EERROR(err = ENOTDIR, "bad mode");
+
+ // fill in the dirbuf
+ if (dirbuf_init(&buf, size))
+ ERROR("failed to init dirbuf");
+
+ // add . and ..
+ // we set the next offset to 2, because all dirent offsets will be larger than that
+ err = dirbuf_add(req, off, &buf, 0, 1, ".", dir_node->inode, S_IFDIR )
+ || dirbuf_add(req, off, &buf, 1, 2, "..", dir_node->inode, S_IFDIR );
+
+ if (err != 0)
+ EERROR(err, "failed to add . and .. dirents");
+
+ // look up all child nodes
+ for (node = fs->inode_table; node->inode; node++) {
+ // skip non-children
+ if (node->parent != dir_node->inode)
+ continue;
+
+ // child node offsets are just inode + 2
+ if ((err = dirbuf_add(req, off, &buf, node->inode + 2, node->inode + 3, node->name, node->inode, node->mode_type)) < 0)
+ EERROR(err, "failed to add dirent for inode=%lu", node->inode);
+
+ // stop if it's full
+ if (err > 0)
+ break;
+ }
+
+ // send it
+ if ((err = -dirbuf_done(req, &buf)))
+ EERROR(err, "failed to send buf");
+
+ // success
+ return;
+
+error:
+ if ((err = fuse_reply_err(req, err)))
+ EWARNING(err, "fuse_reply_err");
+}
/*
* Define our fuse_lowlevel_ops struct.
@@ -109,6 +173,8 @@
.lookup = simple_lookup,
.getattr = simple_getattr,
+
+ .readdir = simple_readdir,
};
struct fuse_lowlevel_ops *simple_init () {