From 1bf64f48067728cc470c3779f7eec78a0ffbd2c5 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 17 Feb 2006 15:49:25 +0000 Subject: [PATCH] fix --- ChangeLog | 6 ++++ example/hello_ll.c | 14 ++++---- include/fuse_lowlevel.h | 25 +++++++------ include/fuse_lowlevel_compat.h | 5 +++ lib/fuse.c | 65 +++++++++++++++++++++------------- lib/fuse_lowlevel.c | 17 +++++++-- lib/fuse_versionscript | 4 +++ 7 files changed, 89 insertions(+), 47 deletions(-) diff --git a/ChangeLog b/ChangeLog index c447832..d6a1d1b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2006-02-17 Miklos Szeredi + + * 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 * 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 @@ struct dirbuf { 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 @@ static void hello_ll_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, 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 @@ struct fuse_lowlevel_ops { /** * 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. * @@ -872,18 +872,14 @@ int fuse_reply_xattr(fuse_req_t req, size_t count); * Filling a buffer in readdir * * ----------------------------------------------------------- */ -/** - * 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 @@ size_t fuse_dirent_size(size_t namelen); * 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 @@ struct fuse_session *fuse_lowlevel_new_compat25(struct fuse_args *args, 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 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 node { struct fuse_dirhandle { pthread_mutex_t lock; struct fuse *fuse; + fuse_req_t req; char *contents; int allocated; unsigned len; @@ -1446,13 +1447,32 @@ static void fuse_opendir(fuse_req_t req, fuse_ino_t ino, 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 @@ static int fill_dir_common(struct fuse_dirhandle *dh, const char *name, } } - 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 @@ static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type, 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 @@ static int readdir_fill(struct fuse *f, fuse_ino_t ino, size_t size, 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 @@ static void fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, 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 @@ char *fuse_add_dirent(char *buf, const char *name, const struct stat *stbuf, 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 @@ static void do_write(fuse_req_t req, fuse_ino_t nodeid, 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 @@ static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, 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.5 { FUSE_2.6 { global: + fuse_add_direntry; fuse_lowlevel_new; fuse_lowlevel_new_compat25; fuse_main_real; @@ -94,4 +95,7 @@ FUSE_2.6 { fuse_opt_insert_arg; fuse_setup; fuse_setup_compat25; + + local: + *; } FUSE_2.5; -- 2.30.2