fix
diff --git a/ChangeLog b/ChangeLog
index c447832..d6a1d1b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2006-02-17  Miklos Szeredi <miklos@szeredi.hu>
+
+	* Lowlevel lib: Unify fuse_dirent_size() and fuse_add_dirent()
+	into a single function fuse_add_direntry().  This cleans up the
+	interface and makes it possible to do stacking.
+
 2006-02-16  Miklos Szeredi <miklos@szeredi.hu>
 
 	* Fix rare race betweeen abort and release caused by failed iget()
diff --git a/example/hello_ll.c b/example/hello_ll.c
index 7682f4e..2213285 100644
--- a/example/hello_ll.c
+++ b/example/hello_ll.c
@@ -75,15 +75,17 @@
     size_t size;
 };
 
-static void dirbuf_add(struct dirbuf *b, const char *name, fuse_ino_t ino)
+static void dirbuf_add(fuse_req_t req, struct dirbuf *b, const char *name,
+                       fuse_ino_t ino)
 {
     struct stat stbuf;
     size_t oldsize = b->size;
-    b->size += fuse_dirent_size(strlen(name));
+    b->size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
     b->p = (char *) realloc(b->p, b->size);
     memset(&stbuf, 0, sizeof(stbuf));
     stbuf.st_ino = ino;
-    fuse_add_dirent(b->p + oldsize, name, &stbuf, b->size);
+    fuse_add_direntry(req, b->p + oldsize, b->size - oldsize, name, &stbuf,
+                      b->size);
 }
 
 #define min(x, y) ((x) < (y) ? (x) : (y))
@@ -108,9 +110,9 @@
         struct dirbuf b;
 
         memset(&b, 0, sizeof(b));
-        dirbuf_add(&b, ".", 1);
-        dirbuf_add(&b, "..", 1);
-        dirbuf_add(&b, hello_name, 2);
+        dirbuf_add(req, &b, ".", 1);
+        dirbuf_add(req, &b, "..", 1);
+        dirbuf_add(req, &b, hello_name, 2);
         reply_buf_limited(req, b.p, b.size, off, size);
         free(b.p);
     }
diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h
index 8338927..bdcbfed 100644
--- a/include/fuse_lowlevel.h
+++ b/include/fuse_lowlevel.h
@@ -525,7 +525,7 @@
     /**
      * Read directory
      *
-     * Send a buffer filled using fuse_add_dirent(), with size not
+     * Send a buffer filled using fuse_add_direntry(), with size not
      * exceeding the requested size.  Send an empty buffer on end of
      * stream.
      *
@@ -873,17 +873,13 @@
  * ----------------------------------------------------------- */
 
 /**
- * Calculate the number of bytes a directory entry takes up
- *
- * @param namelen the length of the entry name
- * @return the number of bytes needed
- */
-size_t fuse_dirent_size(size_t namelen);
-
-/**
  * Add a directory entry to the buffer
  *
- * Buffer needs to be large enough to hold the entry
+ * Buffer needs to be large enough to hold the entry.  Of it's not,
+ * then the entry is not filled in but the size of the entry is still
+ * returned.  The caller can check this by comparing the bufsize
+ * parameter with the returned entry size.  If the entry size is
+ * larger than the buffer size, the operation failed.
  *
  * From the 'stbuf' argument the st_ino field and bits 12-15 of the
  * st_mode field are used.  The other fields are ignored.
@@ -892,14 +888,17 @@
  * could be any marker, that enables the implementation to find a
  * specific point in the directory stream.
  *
+ * @param req request handle
  * @param buf the point where the new entry will be added to the buffer
+ * @param bufsize remaining size of the buffer
  * @param the name of the entry
  * @param stbuf the file attributes
  * @param off the offset of the next entry
- * @return a pointer to the start of the next entry in the buffer
+ * @return the space needed for the entry
  */
-char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
-                      off_t off);
+size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
+                         const char *name, const struct stat *stbuf,
+                         off_t off);
 
 /* ----------------------------------------------------------- *
  * Utility functions                                           *
diff --git a/include/fuse_lowlevel_compat.h b/include/fuse_lowlevel_compat.h
index 0ba0c96..f6e116c 100644
--- a/include/fuse_lowlevel_compat.h
+++ b/include/fuse_lowlevel_compat.h
@@ -62,6 +62,11 @@
                         const struct fuse_lowlevel_ops_compat25 *op,
                         size_t op_size, void *userdata);
 
+size_t fuse_dirent_size(size_t namelen);
+
+char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf,
+                      off_t off);
+
 #ifndef __FreeBSD__
 
 #include <sys/statfs.h>
diff --git a/lib/fuse.c b/lib/fuse.c
index ea17a3d..f930404 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -90,6 +90,7 @@
 struct fuse_dirhandle {
     pthread_mutex_t lock;
     struct fuse *fuse;
+    fuse_req_t req;
     char *contents;
     int allocated;
     unsigned len;
@@ -1446,13 +1447,32 @@
         fuse_reply_open(req, llfi);
 }
 
+static int extend_contents(struct fuse_dirhandle *dh, unsigned minsize)
+{
+    if (minsize > dh->size) {
+        char *newptr;
+        unsigned newsize = dh->size;
+        if (!newsize)
+            newsize = 1024;
+        while (newsize < minsize)
+            newsize *= 2;
+
+        newptr = (char *) realloc(dh->contents, newsize);
+        if (!newptr) {
+            dh->error = -ENOMEM;
+            return -1;
+        }
+        dh->contents = newptr;
+        dh->size = newsize;
+    }
+    return 0;
+}
+
 static int fill_dir_common(struct fuse_dirhandle *dh, const char *name,
                            const struct stat *statp, off_t off)
 {
     struct stat stbuf;
-    unsigned namelen = strlen(name);
-    unsigned entsize;
-    unsigned newlen;
+    size_t newlen;
 
     if (statp)
         stbuf = *statp;
@@ -1473,31 +1493,24 @@
         }
     }
 
-    entsize = fuse_dirent_size(namelen);
-    newlen = dh->len + entsize;
-
     if (off) {
+        if (extend_contents(dh, dh->needlen) == -1)
+            return 1;
+
         dh->filled = 0;
+        newlen = dh->len + fuse_add_direntry(dh->req, dh->contents + dh->len,
+                                             dh->needlen - dh->len, name,
+                                             &stbuf, off);
         if (newlen > dh->needlen)
             return 1;
-    }
-
-    if (newlen > dh->size) {
-        char *newptr;
-
-        if (!dh->size)
-            dh->size = 1024;
-        while (newlen > dh->size)
-            dh->size *= 2;
-
-        newptr = (char *) realloc(dh->contents, dh->size);
-        if (!newptr) {
-            dh->error = -ENOMEM;
+    } else {
+        newlen = dh->len + fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
+        if (extend_contents(dh, newlen) == -1)
             return 1;
-        }
-        dh->contents = newptr;
+
+        fuse_add_direntry(dh->req, dh->contents + dh->len, dh->size - dh->len,
+                          name, &stbuf, newlen);
     }
-    fuse_add_dirent(dh->contents + dh->len, name, &stbuf, off ? off : newlen);
     dh->len = newlen;
     return 0;
 }
@@ -1521,8 +1534,8 @@
     return dh->error;
 }
 
-static int readdir_fill(struct fuse *f, fuse_ino_t ino, size_t size,
-                        off_t off, struct fuse_dirhandle *dh,
+static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
+                        size_t size, off_t off, struct fuse_dirhandle *dh,
                         struct fuse_file_info *fi)
 {
     int err = -ENOENT;
@@ -1534,11 +1547,13 @@
         dh->error = 0;
         dh->needlen = size;
         dh->filled = 1;
+        dh->req = req;
         err = -ENOSYS;
         if (f->op.readdir)
             err = f->op.readdir(path, dh, fill_dir, off, fi);
         else if (f->op.getdir)
             err = f->op.getdir(path, dh, fill_dir_old);
+        dh->req = NULL;
         if (!err)
             err = dh->error;
         if (err)
@@ -1563,7 +1578,7 @@
         dh->filled = 0;
 
     if (!dh->filled) {
-        int err = readdir_fill(f, ino, size, off, dh, &fi);
+        int err = readdir_fill(f, req, ino, size, off, dh, &fi);
         if (err) {
             reply_err(req, err);
             goto out;
diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c
index eeb296c..12f6c82 100644
--- a/lib/fuse_lowlevel.c
+++ b/lib/fuse_lowlevel.c
@@ -186,6 +186,18 @@
     return buf + entsize;
 }
 
+size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
+                         const char *name, const struct stat *stbuf, off_t off)
+{
+    size_t entsize;
+
+    (void) req;
+    entsize = fuse_dirent_size(strlen(name));
+    if (entsize <= bufsize && buf)
+        fuse_add_dirent(buf, name, stbuf, off);
+    return entsize;
+}
+
 static void convert_statfs(const struct statvfs *stbuf,
                            struct fuse_kstatfs *kstatfs)
 {
@@ -526,8 +538,7 @@
     fi.writepage = arg->write_flags & 1;
 
     if (req->f->op.write)
-        req->f->op.write(req, nodeid, PARAM(arg), arg->size,
-                                arg->offset, &fi);
+        req->f->op.write(req, nodeid, PARAM(arg), arg->size, arg->offset, &fi);
     else
         fuse_reply_err(req, ENOSYS);
 }
@@ -654,7 +665,7 @@
 
     if (req->f->op.setxattr)
             req->f->op.setxattr(req, nodeid, name, value, arg->size,
-                                       arg->flags);
+                                arg->flags);
     else
         fuse_reply_err(req, ENOSYS);
 }
diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript
index 6e0ab13..b6e6e18 100644
--- a/lib/fuse_versionscript
+++ b/lib/fuse_versionscript
@@ -85,6 +85,7 @@
 
 FUSE_2.6 {
 	global:
+		fuse_add_direntry;
 		fuse_lowlevel_new;
 		fuse_lowlevel_new_compat25;
 		fuse_main_real;
@@ -94,4 +95,7 @@
 		fuse_opt_insert_arg;
 		fuse_setup;
 		fuse_setup_compat25;
+
+	local:
+		 *;
 } FUSE_2.5;