working simple_readdir
authorTero Marttila <terom@fixme.fi>
Fri, 26 Sep 2008 21:13:35 +0300
changeset 8 21bb5cdca4db
parent 7 3a603d755bcb
child 9 fbd239431dbe
working simple_readdir
src/lib/error.h
src/lib/log.h
src/simple.c
src/simple.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/error.h	Fri Sep 26 21:13:35 2008 +0300
@@ -0,0 +1,8 @@
+#ifndef LIB_ERROR_H
+#define LIB_ERROR_H
+
+#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)
+
+#endif /* LIB_ERROR_H */
--- a/src/lib/log.h	Fri Sep 26 20:39:51 2008 +0300
+++ b/src/lib/log.h	Fri Sep 26 21:13:35 2008 +0300
@@ -1,3 +1,5 @@
+#ifndef LIB_LOG_H
+#define LIB_LOG_H
 
 /*
  * error handling
@@ -35,12 +37,10 @@
 #define eerr_func(func, err, ...)   _generic_err(       1,  func,   err,__VA_ARGS__ )
 
 /*
- * error(func + colon + msg, ...) + goto error
- * err = negative error code
+ * Legacy...
  */
-#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)
+#include "error.h"
+
 #define FATAL(...) err_func_exit(__func__, __VA_ARGS__)
 #define PFATAL(...) perr_func_exit(__func__, __VA_ARGS__)
 #define WARNING(...) err_func(__func__, __VA_ARGS__)
@@ -68,3 +68,4 @@
 #define INFO(...) (void) (0)
 #endif
 
+#endif /* LIB_LOG_H */
--- 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 () {
--- a/src/simple.h	Fri Sep 26 20:39:51 2008 +0300
+++ b/src/simple.h	Fri Sep 26 21:13:35 2008 +0300
@@ -5,7 +5,7 @@
  * A simple static in-memory filesystem structure.
  */
 
-#include <fuse/fuse_lowlevel.h>
+#include "evfuse.h"
 
 /*
  * A simple file/dir.