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;