diff -r 3a603d755bcb -r 21bb5cdca4db src/simple.c --- 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 #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 () {